﻿/************************************************************************

   Extended Silverlight Toolkit

   Copyright (C) 2010-2012 Xceed Software Inc.

   This program is provided to you under the terms of the Microsoft Public
   License (Ms-PL) as published at http://extendedsilverlight.codeplex.com/license

   Please purchase a commercial version of this toolkit if you are using
   it in a commercial product. The commercial versions support the project,
   and also include more features for each control, priority support,
   source code, updates, removed watermark, and a proprietary license.

   Visit http://xceed.com and follow @datagrid on Twitter.

  **********************************************************************/

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Threading;
using Xceed.Silverlight.Data;
using Xceed.Silverlight.Data.Stats;
using Xceed.Silverlight.Utils;
using Xceed.Silverlight.Compatibility;
using System.Collections;

namespace Xceed.Silverlight.DataGrid
{
  #region Metadata

  [TemplatePart( Name = "dataGridPanelHost", Type = typeof( Border ) )]
  [TemplatePart( Name = "verticalScrollBar", Type = typeof( ScrollBar ) )]
  [TemplatePart( Name = "horizontalScrollBar", Type = typeof( ScrollBar ) )]

  [TemplateVisualState( GroupName = "RequestStates", Name = "NoPendingRequests" )]
  [TemplateVisualState( GroupName = "RequestStates", Name = "RequestsPending" )]

  [TemplateVisualState( GroupName = "LicensingStates", Name = "Licensed" )]
  [TemplateVisualState( GroupName = "LicensingStates", Name = "NotLicensed" )]

  [TemplateVisualState( GroupName = "UnconstrainedStates", Name = "Constrained" )]
  [TemplateVisualState( GroupName = "UnconstrainedStates", Name = "Unconstrained" )]

  // Blend has to be able to create an instance of this for the style edit so it can't be typeof( Row )
  [StyleTypedProperty( Property = "RowStyle", StyleTargetType = typeof( DataRow ) )]
  [StyleTypedProperty( Property = "CellStyle", StyleTargetType = typeof( DataCell ) )]
  [StyleTypedProperty( Property = "ColumnManagerRowStyle", StyleTargetType = typeof( ColumnManagerRow ) )]
  [StyleTypedProperty( Property = "ColumnManagerCellStyle", StyleTargetType = typeof( ColumnManagerCell ) )]

  #endregion //Metadata

  public partial class DataGridControl : ControlBase, INotifyPropertyChanged, ISupportInitialize, IDataGridContextHelper
  {

    internal const int DefaultTopLevelGroupZIndex = 100;
    internal const int DefaultColumnBackgroundZIndex = 100;
    internal const int DefaultHeaderGroupByControlPosition = 0;
    internal const int DefaultHeaderFilterRowPosition = 1;
    internal const int DefaultHeaderColumnManagerRowPosition = 2;
    internal const int DefaultHeaderInsertionRowPosition = 3;
    internal const int DefaultFooterNotificationControlPosition = 0;
    internal const double DefaultGroupSublevelIndent = 7d;
    internal const string AllowGroupNavigationPropertyName = "AllowGroupNavigation";
    internal const string GroupNavigationModesPropertyName = "GroupNavigationModes";
    internal const string AllowGroupCollapsingPropertyName = "AllowGroupCollapsing";

    internal static readonly string LicensingStateLicensed = "Licensed";
    internal static readonly string LicensingStateNotLicensed = "NotLicensed";
    internal static readonly string RequestPendingStatePending = "RequestsPending";
    internal static readonly string RequestPendingStateNotPending = "NoPendingRequests";
    internal static readonly string UnconstrainedStateConstrained = "Constrained";
    internal static readonly string UnconstrainedStateUnconstrained = "Unconstrained";

    private static readonly Guid GroupHeaderControlKey = Guid.NewGuid();

    static DataGridControl()
    {

      bool allowFixedColumns = true;

      DataGridControl.AllowFixedColumnsProperty = DependencyProperty.Register(
        "AllowFixedColumns",
        typeof( bool ),
        typeof( DataGridControl ),
        new PropertyMetadata( allowFixedColumns, new PropertyChangedCallback( DataGridControl.OnAllowFixedColumnsChanged ) ) );

      FixedColumnToggleButtonVisibility defaultFixedColumnToggleButtonVisibility = ( allowFixedColumns )
       ? FixedColumnToggleButtonVisibility.Auto
       : FixedColumnToggleButtonVisibility.Never;

      DataGridControl.FixedColumnToggleButtonVisibilityProperty = DependencyProperty.Register(
        "FixedColumnToggleButtonVisibility",
        typeof( FixedColumnToggleButtonVisibility ),
        typeof( DataGridControl ),
        new PropertyMetadata( defaultFixedColumnToggleButtonVisibility, new PropertyChangedCallback( DataGridControl.OnFixedColumnToggleButtonVisibilityChanged ) ) );
    }

    public DataGridControl()
    {
      this.VisualStateHelper = new VisualStateHelper( this );

      bool isLicensed = true;
      this.VisualStateHelper.GoToLicensedState( isLicensed
                                                ? DataGridControl.LicensingStateLicensed
                                                : DataGridControl.LicensingStateNotLicensed, true );

      this.DefaultStyleKey = typeof( DataGridControl );
      m_timer = new DispatcherTimer();
      m_timer.Tick += this.OnTimerTick;

      this.DataGridPanel = new DataGridPanel();
      this.SetUnconstrainedState( false );
      this.DataGridPanel.UnconstrainedStateChanged += this.OnDataGridPanelUnconstrainedStateChanged;
      this.DataGridPanel.MouseWheel += this.OnDataGridPanelMouseWheel;

      this.DataGridContext = new DataGridContext( this );
      ObservableCollection<SelectionRange> selectionRangeCollection = ( ObservableCollection<SelectionRange> )this.DataGridContext.SelectedRanges;
      this.DataGridContext.SelectedItems = new SelectedItemCollection( this, selectionRangeCollection );
      selectionRangeCollection.CollectionChanged += new NotifyCollectionChangedEventHandler( this.OnSelectedRangesChanged );

      this.DataGridContext.Columns.CollectionChanged += new NotifyCollectionChangedEventHandler( this.OnColumnsCollectionChanged );

      m_fixedHeaders = new ObservableCollection<UIElement>();
      m_fixedFooters = new ObservableCollection<UIElement>();
      m_fixedFooters.CollectionChanged += this.OnFixedCollectionChanged;
      m_fixedHeaders.CollectionChanged += this.OnFixedCollectionChanged;

      this.StatFunctions.CollectionChanged += new NotifyCollectionChangedEventHandler( this.StatFunctionsCollectionChanged );

      this.EventManager.AddHandler( Row.OnMouseEnterRowEvent, this.OnMouseEnterRow );
      this.EventManager.AddHandler( Row.OnMouseLeaveRowEvent, this.OnMouseLeaveRow );
      this.EventManager.AddHandler( Row.OnRowCellStyleChangedEvent, this.OnCellStyleChangedFromRow );
      this.EventManager.AddHandler( ColumnManagerRow.OnAllowColumnResizeChangedEvent, this.OnAllowColumnResizeChangedFromColumnManagerRow );
      this.EventManager.AddHandler( ColumnManagerRow.OnDefaultColumnTitleTemplateChangedEvent, this.OnDefaultColumnTitleTemplateChangedFromColumnManagerRow );
      this.EventManager.AddHandler( EditableRoutedEvents.RequestBeginEditEvent, this.OnRequestBeginEdit );
      this.EventManager.AddHandler( EditableRoutedEvents.RequestEndEditEvent, this.OnRequestEndEdit );
      this.EventManager.AddHandler( EditableRoutedEvents.RequestCancelEditEvent, this.OnRequestCancelEdit );
      this.EventManager.AddHandler( EditableRoutedEvents.RequestPropertyChangedCommitEvent, this.OnRequestPropertyChangedCommit );
      this.EventManager.AddHandler( EditableRoutedEvents.ActivatingCellEditorEvent, this.OnActivatingCellEditor );
      this.EventManager.AddHandler( Cell.OnMouseEnterCellEvent, this.OnMouseEnterCell );
      this.EventManager.AddHandler( Cell.OnMouseLeaveCellEvent, this.OnMouseLeaveCell );
      this.EventManager.AddHandler( ColumnManagerCell.OnColumnManagerCellIsPressedChangedEvent, this.OnColumnManagerCellIsPressedChanged );
      this.EventManager.AddHandler( ColumnManagerCell.OnColumnResizingThumbDragEvent, this.OnColumnResizingThumbDrag );
      this.EventManager.AddHandler( GroupHeaderControl.OnMouseEnterGroupHeaderEvent, this.OnMouseEnterGroupHeader );
      this.EventManager.AddHandler( GroupHeaderControl.OnMouseLeaveGroupHeaderEvent, this.OnMouseLeaveGroupHeader );
      this.EventManager.AddHandler( GroupHeaderControl.OnGroupSearchBoxFocusEvent, this.OnGroupSearchBoxFocus );
      this.EventManager.AddHandler( GroupHeaderControl.OnToggleExpansionGroupEvent, this.OnToggleExpansionGroup );
      this.EventManager.AddHandler( GroupHeaderControl.OnExpandGroupEvent, this.OnExpandGroup );
      this.EventManager.AddHandler( GroupHeaderControl.OnCollapseGroupEvent, this.OnCollapseGroup );
      this.EventManager.AddHandler( GroupHeaderControl.OnGotoPreviousGroupEvent, this.OnGotoPreviousGroup );
      this.EventManager.AddHandler( GroupHeaderControl.OnGotoNextGroupEvent, this.OnGotoNextGroup );
      this.EventManager.AddHandler( GroupNavigationSearchBox.OnSearchGroupEvent, this.OnGotoSearchGroup );
      this.EventManager.AddHandler( DataGridPanel.ColumnAdded, this.OnColumnAdded );
      this.EventManager.AddHandler( DataGridPanel.ColumnRemoved, this.OnColumnRemoved );

      this.Loaded += new RoutedEventHandler( OnDataGridLoaded );
      this.Unloaded += new RoutedEventHandler( OnDataGridUnLoaded );

      m_rowUpdateManager = new RowUpdateManager( this );
      m_columnUpdateManager = new ColumnUpdateManager( this );
      m_editingManager = new EditingManager( this );
      m_hardwareEventManager = new HardwareEventsManager( this );

      m_dataGridViewModel = new DataGridViewModel();
      m_dataGridViewModel.Initialize();

      this.OnItemsSourceChanged( null );

      this.RefreshDefaultHeadersFooters();
    }

    #region AllowColumnReorder Property

    public static readonly DependencyProperty AllowColumnReorderProperty = DependencyProperty.Register(
      "AllowColumnReorder",
      typeof( bool ),
      typeof( DataGridControl ),
      new PropertyMetadata( true, null ) );

    public bool AllowColumnReorder
    {
      get
      {
        return ( bool )this.GetValue( DataGridControl.AllowColumnReorderProperty );
      }
      set
      {
        this.SetValue( DataGridControl.AllowColumnReorderProperty, value );
      }
    }

    #endregion // AllowColumnReorder Property

    #region AllowColumnResize Property

    public static readonly DependencyProperty AllowColumnResizeProperty = DependencyProperty.Register(
      "AllowColumnResize",
      typeof( bool ),
      typeof( DataGridControl ),
      new PropertyMetadata( true, new PropertyChangedCallback( DataGridControl.OnAllowColumnResizeChanged ) ) );

    public bool AllowColumnResize
    {
      get
      {
        return ( bool )this.GetValue( DataGridControl.AllowColumnResizeProperty );
      }
      set
      {
        this.SetValue( DataGridControl.AllowColumnResizeProperty, value );
      }
    }

    private static void OnAllowColumnResizeChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e )
    {
      var dataGridControl = ( DataGridControl )sender;
      dataGridControl.InvalidateColumnManagerRowAllowColumnResize();
    }

    #endregion // AllowColumnResize Property

    #region AllowGroup Property

    public static readonly DependencyProperty AllowGroupProperty = DependencyProperty.Register(
      "AllowGroup",
      typeof( bool ),
      typeof( DataGridControl ),
      new PropertyMetadata( true, new PropertyChangedCallback( DataGridControl.OnAllowGroupChanged ) ) );

    public bool AllowGroup
    {
      get
      {
        return ( bool )this.GetValue( DataGridControl.AllowGroupProperty );
      }
      set
      {
        this.SetValue( DataGridControl.AllowGroupProperty, value );
      }
    }

    private static void OnAllowGroupChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e )
    {
      var dataGridControl = ( DataGridControl )sender;
      dataGridControl.UpdateAllGroupByItemRemoveButtonVisibility();
    }

    #endregion // AllowGroup Property

    #region AllowGroupCollapsing Property

    public static readonly DependencyProperty AllowGroupCollapsingProperty = DependencyProperty.Register(
      "AllowGroupCollapsing",
      typeof( bool ),
      typeof( DataGridControl ),
      new PropertyMetadata( true, new PropertyChangedCallback( DataGridControl.OnAllowGroupCollapsingChanged ) ) );

    public bool AllowGroupCollapsing
    {
      get
      {
        return ( bool )this.GetValue( DataGridControl.AllowGroupCollapsingProperty );
      }
      set
      {
        this.SetValue( DataGridControl.AllowGroupCollapsingProperty, value );
      }
    }

    private static void OnAllowGroupCollapsingChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e )
    {
      var dataGridControl = ( DataGridControl )sender;
      dataGridControl.UpdateAllGroupContainerNavigationToolsVisibility();
      dataGridControl.RaisePropertyChanged( DataGridControl.AllowGroupCollapsingPropertyName );
    }

    #endregion // AllowGroupCollapsing Property

    #region AllowGroupNavigation Property

    public static readonly DependencyProperty AllowGroupNavigationProperty = DependencyProperty.Register(
      "AllowGroupNavigation",
      typeof( bool ),
      typeof( DataGridControl ),
      new PropertyMetadata( true, new PropertyChangedCallback( DataGridControl.OnAllowGroupNavigationChanged ) ) );

    public bool AllowGroupNavigation
    {
      get
      {
        return ( bool )this.GetValue( DataGridControl.AllowGroupNavigationProperty );
      }
      set
      {
        this.SetValue( DataGridControl.AllowGroupNavigationProperty, value );
      }
    }

    private static void OnAllowGroupNavigationChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e )
    {
      DataGridControl dataGridControl = ( DataGridControl )sender;
      dataGridControl.UpdateAllGroupContainerNavigationToolsVisibility();
      dataGridControl.RaisePropertyChanged( DataGridControl.AllowGroupNavigationPropertyName );
    }

    #endregion // AllowGroupNavigation Property

    #region AllowSort Property

    public static readonly DependencyProperty AllowSortProperty = DependencyProperty.Register(
      "AllowSort",
      typeof( bool ),
      typeof( DataGridControl ),
      new PropertyMetadata( true, null ) );

    public bool AllowSort
    {
      get
      {
        return ( bool )this.GetValue( DataGridControl.AllowSortProperty );
      }
      set
      {
        this.SetValue( DataGridControl.AllowSortProperty, value );
      }
    }

    #endregion // AllowSort Property

    #region AllowFixedColumns Property

    public static readonly DependencyProperty AllowFixedColumnsProperty;

    public bool AllowFixedColumns
    {
      get
      {
        return ( bool )this.GetValue( DataGridControl.AllowFixedColumnsProperty );
      }
      set
      {
        this.SetValue( DataGridControl.AllowFixedColumnsProperty, value );
      }
    }

    private static void OnAllowFixedColumnsChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e )
    {
      DataGridControl datagridControl = ( DataGridControl )sender;
      datagridControl.RefreshFixedColumnToggleButtonVisibility();
    }

    #endregion // AllowFixedColumns Property

    #region AlternatingRowBackground Property

    public static readonly DependencyProperty AlternatingRowBackgroundProperty = DependencyProperty.Register(
      "AlternatingRowBackground",
      typeof( Brush ),
      typeof( DataGridControl ),
      new PropertyMetadata( null, new PropertyChangedCallback( DataGridControl.OnAlternatingRowBackgroundChanged ) ) );

    public Brush AlternatingRowBackground
    {
      get
      {
        return ( Brush )this.GetValue( DataGridControl.AlternatingRowBackgroundProperty );
      }
      set
      {
        this.SetValue( DataGridControl.AlternatingRowBackgroundProperty, value );
      }
    }

    private static void OnAlternatingRowBackgroundChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e )
    {
      var dataGridControl = ( DataGridControl )sender;
      dataGridControl.OnRowsAlternatingBackgroundChange( dataGridControl.AlternatingRowBackground );
    }

    #endregion // AlternatingRowBackground Property

    #region AnimationSettings Property

    public static readonly DependencyProperty AnimationSettingsProperty = DependencyProperty.Register(
      "AnimationSettings",
      typeof( DataGridAnimationSettings ),
      typeof( DataGridControl ),
      new PropertyMetadata( DataGridAnimationSettings.Default ) );

    public DataGridAnimationSettings AnimationSettings
    {
      get
      {
        return ( DataGridAnimationSettings )this.GetValue( DataGridControl.AnimationSettingsProperty );
      }
      set
      {
        this.SetValue( DataGridControl.AnimationSettingsProperty, value );
      }
    }

    #endregion

    #region AreAlternateStatesEnabled Property

    public static readonly DependencyProperty AreAlternateStatesEnabledProperty = DependencyProperty.Register(
      "AreAlternateStatesEnabled",
      typeof( bool ),
      typeof( DataGridControl ),
      new PropertyMetadata( true, DataGridControl.OnAreAlternateStatesEnabledChanged ) );

    public bool AreAlternateStatesEnabled
    {
      get
      {
        return ( bool )this.GetValue( DataGridControl.AreAlternateStatesEnabledProperty );
      }
      set
      {
        this.SetValue( DataGridControl.AreAlternateStatesEnabledProperty, value );
      }
    }

    private static void OnAreAlternateStatesEnabledChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e )
    {
      DataGridControl dataGridControl = sender as DataGridControl;

      if( dataGridControl == null )
        return;

      // Reset the LayoutManager only if in DesignTime
      if( !Xceed.Utils.Licensing.DesignerProperties.GetIsInDesignMode() )
        return;

    }

    #endregion

    #region AutoAlignColumns Property

    public static readonly DependencyProperty AutoAlignColumnsProperty = DependencyProperty.Register(
      "AutoAlignColumns",
      typeof( bool ),
      typeof( DataGridControl ),
      new PropertyMetadata( true, new PropertyChangedCallback( DataGridControl.OnAutoAlignColumnsChanged ) ) );

    public bool AutoAlignColumns
    {
      get
      {
        return ( bool )this.GetValue( DataGridControl.AutoAlignColumnsProperty );
      }
      set
      {
        this.SetValue( DataGridControl.AutoAlignColumnsProperty, value );
      }
    }

    private static void OnAutoAlignColumnsChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e )
    {
      var dataGridControl = ( DataGridControl )sender;

      // Update each column
      foreach( ColumnContainer columnContainer in dataGridControl.DataGridPanel.RenderedColumns )
      {
        dataGridControl.UpdateCellHorizontalContentAlignment( columnContainer.Column );
      }
    }

    #endregion // AutoAlignColumns Property

    #region AutoCreateColumns Property

    public static readonly DependencyProperty AutoCreateColumnsProperty = DependencyProperty.Register(
      "AutoCreateColumns",
      typeof( bool ),
      typeof( DataGridControl ),
      new PropertyMetadata( ( bool )true, new PropertyChangedCallback( DataGridControl.OnAutoCreateColumnsPropertyChanged ) ) );

    public bool AutoCreateColumns
    {
      get
      {
        return ( bool )this.GetValue( DataGridControl.AutoCreateColumnsProperty );
      }
      set
      {
        this.SetValue( DataGridControl.AutoCreateColumnsProperty, value );
      }
    }

    private static void OnAutoCreateColumnsPropertyChanged( object sender, DependencyPropertyChangedEventArgs e )
    {
      if( Xceed.Utils.Licensing.DesignerProperties.GetIsInDesignMode() )
      {
        DataGridControl dataGridControl = ( DataGridControl )sender;

        if( ( bool )e.NewValue )
        {
          dataGridControl.GenerateColumnsForDataSource();
        }
        else
        {
          dataGridControl.RemoveAutoGeneratedColumns();
        }
      }
    }

    #endregion

    #region CellStyle Property

    public static readonly DependencyProperty CellStyleProperty = DependencyProperty.Register(
      "CellStyle",
      typeof( Style ),
      typeof( DataGridControl ),
      new PropertyMetadata( null, new PropertyChangedCallback( DataGridControl.OnCellStyleChanged ) ) );

    public Style CellStyle
    {
      get
      {
        return ( Style )this.GetValue( DataGridControl.CellStyleProperty );
      }
      set
      {
        this.SetValue( DataGridControl.CellStyleProperty, value );
      }
    }

    private static void OnCellStyleChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e )
    {
      var dataGridControl = ( DataGridControl )sender;
      dataGridControl.RefreshColumns( true );
    }

    #endregion // CellStyle Property

    #region ClipboardCopyMode Property

    public static readonly DependencyProperty ClipboardCopyModeProperty = DependencyProperty.Register(
      "ClipboardCopyMode",
      typeof( DataGridClipboardCopyMode ),
      typeof( DataGridControl ),
      new PropertyMetadata( DataGridClipboardCopyMode.ExcludeHeader ) );

    public DataGridClipboardCopyMode ClipboardCopyMode
    {
      get
      {
        return ( DataGridClipboardCopyMode )this.GetValue( DataGridControl.ClipboardCopyModeProperty );
      }
      set
      {
        this.SetValue( DataGridControl.ClipboardCopyModeProperty, value );
      }
    }

    #endregion // ClipboardCopyMode Property

    #region ColumnManagerCellStyle Property

    public static readonly DependencyProperty ColumnManagerCellStyleProperty = DependencyProperty.Register(
      "ColumnManagerCellStyle",
      typeof( Style ),
      typeof( DataGridControl ),
      new PropertyMetadata( null, new PropertyChangedCallback( DataGridControl.OnColumnManagerCellStyleChanged ) ) );

    public Style ColumnManagerCellStyle
    {
      get
      {
        return ( Style )this.GetValue( DataGridControl.ColumnManagerCellStyleProperty );
      }
      set
      {
        this.SetValue( DataGridControl.ColumnManagerCellStyleProperty, value );
      }
    }

    private static void OnColumnManagerCellStyleChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e )
    {
      var dataGridControl = ( DataGridControl )sender;
      dataGridControl.RefreshColumns( true );
    }

    #endregion // ColumnManagerCellStyle Property

    #region ColumnManagerRowStyle Property

    public static readonly DependencyProperty ColumnManagerRowStyleProperty = DependencyProperty.Register(
      "ColumnManagerRowStyle",
      typeof( Style ),
      typeof( DataGridControl ),
      new PropertyMetadata( null, new PropertyChangedCallback( DataGridControl.OnColumnManagerRowStyleChanged ) ) );

    public Style ColumnManagerRowStyle
    {
      get
      {
        return ( Style )this.GetValue( DataGridControl.ColumnManagerRowStyleProperty );
      }
      set
      {
        this.SetValue( DataGridControl.ColumnManagerRowStyleProperty, value );
      }
    }

    private static void OnColumnManagerRowStyleChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e )
    {
      var dataGridControl = ( DataGridControl )sender;
      ColumnManagerRowVisitor visitor = new ColumnManagerRowVisitor( ( row ) => row.SetRowStyle( dataGridControl.ColumnManagerRowStyle ) );
      dataGridControl.DataGridPanel.Accept( visitor );
    }

    #endregion // ColumnManagerRowStyle Property

    #region ColumnWidth Property

    public static readonly DependencyProperty ColumnWidthProperty = DependencyProperty.Register(
      "ColumnWidth",
      typeof( double ),
      typeof( DataGridControl ),
      new PropertyMetadata( 100d ) );

    public double ColumnWidth
    {
      get
      {
        return ( double )this.GetValue( DataGridControl.ColumnWidthProperty );
      }
      set
      {
        this.SetValue( DataGridControl.ColumnWidthProperty, value );
      }
    }

    #endregion // ColumnWidth Property

    #region ComputedHorizontalScrollBarVisibility Property

    public Visibility ComputedHorizontalScrollBarVisibility
    {
      get
      {
        return m_horizontalScrollBarVisibility;
      }
      private set
      {
        if( value != m_horizontalScrollBarVisibility )
        {
          m_horizontalScrollBarVisibility = value;
          this.RaisePropertyChanged( "ComputedHorizontalScrollBarVisibility" );
        }
      }
    }

    private Visibility m_horizontalScrollBarVisibility = Visibility.Visible;

    #endregion

    #region ComputedVerticalScrollBarVisibility Property

    public Visibility ComputedVerticalScrollBarVisibility
    {
      get
      {
        return m_verticalScrollBarVisibility;
      }
      private set
      {
        if( value != m_verticalScrollBarVisibility )
        {
          m_verticalScrollBarVisibility = value;
          this.RaisePropertyChanged( "ComputedVerticalScrollBarVisibility" );
        }
      }
    }

    private Visibility m_verticalScrollBarVisibility = Visibility.Visible;

    #endregion

    #region CurrentColumn Dependency Property

    public static readonly DependencyProperty CurrentColumnProperty = DependencyProperty.Register(
      "CurrentColumn",
      typeof( Column ),
      typeof( DataGridControl ),
      new PropertyMetadata( null, new PropertyChangedCallback( DataGridControl.OnCurrentColumnChanged ) ) );

    public Column CurrentColumn
    {
      get
      {
        return ( Column )this.GetValue( DataGridControl.CurrentColumnProperty );
      }
      set
      {
        this.SetValue( DataGridControl.CurrentColumnProperty, value );
      }
    }

    private static void OnCurrentColumnChanged( object sender, DependencyPropertyChangedEventArgs args )
    {
      DataGridControl dataGrid = ( DataGridControl )sender;
      Column oldColumn = ( Column )args.OldValue;
      Column newColumn = ( Column )args.NewValue;

      dataGrid.DataGridContext.SyncProperty( () => dataGrid.DataGridContext.CurrentColumn = newColumn );

      dataGrid.UpdateElementsCurrentState( oldColumn );

      object newCurrentElement = dataGrid.UpdateCurrentInternal( oldColumn, newColumn );
      dataGrid.EnsureCurrentIsFocused( newCurrentElement );

      var inspector = CellEditorVisibilityInspector.Create( dataGrid );
      if( oldColumn != null )
      {
        inspector = inspector.Check( oldColumn );
      }

      if( newColumn != null )
      {
        inspector = inspector.Check( newColumn );
      }

      dataGrid.UpdateCellsEditorVisibility( inspector );
      dataGrid.CheckEditTriggers();
    }

    #endregion

    #region CurrentItem Dependency Property

    public static readonly DependencyProperty CurrentItemProperty = DependencyProperty.Register(
      "CurrentItem",
      typeof( object ),
      typeof( DataGridControl ),
      new PropertyMetadata( null, new PropertyChangedCallback( DataGridControl.OnCurrentItemChanged ) ) );

    public object CurrentItem
    {
      get
      {
        return ( object )this.GetValue( DataGridControl.CurrentItemProperty );
      }
      set
      {
        this.SetValue( DataGridControl.CurrentItemProperty, value );
      }
    }

    private static void OnCurrentItemChanged( object sender, DependencyPropertyChangedEventArgs args )
    {
      DataGridControl dataGrid = ( DataGridControl )sender;

      dataGrid.DataGridContext.SyncProperty( () => dataGrid.DataGridContext.CurrentItem = args.NewValue );
      DataGridPath newDataGridPath = ( args.NewValue != null ) ? dataGrid.DataGridContext.GetPathFromItem( args.NewValue ) : null;
      dataGrid.DataGridContext.SyncProperty( () => dataGrid.CurrentPath = newDataGridPath );
      dataGrid.DataGridContext.SyncProperty( () => dataGrid.DataGridContext.CurrentPath = newDataGridPath );
    }

    #endregion

    #region CurrentPath Dependency Property

    public static readonly DependencyProperty CurrentPathProperty = DependencyProperty.Register(
      "CurrentPath",
      typeof( DataGridPath ),
      typeof( DataGridControl ),
      new PropertyMetadata( null, new PropertyChangedCallback( DataGridControl.OnCurrentPathChanged ) ) );

    public DataGridPath CurrentPath
    {
      get
      {
        return ( DataGridPath )this.GetValue( DataGridControl.CurrentPathProperty );
      }
      set
      {
        this.SetValue( DataGridControl.CurrentPathProperty, value );
      }
    }

    private static void OnCurrentPathChanged( object sender, DependencyPropertyChangedEventArgs args )
    {
      DataGridControl dataGrid = ( DataGridControl )sender;

      DataPath oldPath = dataGrid.DataGridContext.GetActualDataPathOrDataPath( ( DataGridPath )args.OldValue );
      DataPath newPath = dataGrid.DataGridContext.GetActualDataPathOrDataPath( ( DataGridPath )args.NewValue );

      // We only need to apply changes if the current element changed. Since 
      // two DataGridPath may target the same underlying item, we must compare
      // for equality and not reference equality.
      if( object.Equals( oldPath, newPath ) )
        return;

      dataGrid.DataGridContext.SyncProperty( () => dataGrid.DataGridContext.CurrentPath = ( DataGridPath )args.NewValue );
      object newCurrentItem = (newPath != null) ? dataGrid.DataGridContext.DataSource.DataHelper.ConvertBack( newPath ) : null;
      dataGrid.DataGridContext.SyncProperty( () => dataGrid.CurrentItem = newCurrentItem );
      dataGrid.DataGridContext.SyncProperty( () => dataGrid.DataGridContext.CurrentItem = newCurrentItem );

      dataGrid.UpdateElementsCurrentState( oldPath, newPath );

      object newCurrentElement = dataGrid.UpdateCurrentInternal( oldPath, newPath );
      dataGrid.EnsureCurrentIsFocused( newCurrentElement );

      var inspector = CellEditorVisibilityInspector.Create( dataGrid );

      if( oldPath != null )
      {
        var row = dataGrid.GetContainerFromPath( oldPath ) as EditableRow;
        if( row != null )
        {
          inspector = inspector.Check( row );
        }
      }

      if( newPath != null )
      {
        var row = dataGrid.GetContainerFromPath( newPath ) as EditableRow;
        if( row != null )
        {
          inspector = inspector.Check( row );
        }
      }

      dataGrid.UpdateCellsEditorVisibility( inspector );
      dataGrid.CheckEditTriggers();
    }

    #endregion

    #region DataGridContext Property

    public DataGridContext DataGridContext
    {
      get;
      private set;
    }

    #endregion //DataGridContext Property

    #region DefaultGroupConfiguration Property

    public static readonly DependencyProperty DefaultGroupConfigurationProperty = DependencyProperty.Register(
      "DefaultGroupConfiguration",
      typeof( DataGridGroupConfiguration ),
      typeof( DataGridControl ),
      new PropertyMetadata( ( DataGridGroupConfiguration )null, new PropertyChangedCallback( DataGridControl.OnDefaultGroupConfigurationChanged ) ) );

    public DataGridGroupConfiguration DefaultGroupConfiguration
    {
      get
      {
        return ( DataGridGroupConfiguration )this.GetValue( DataGridControl.DefaultGroupConfigurationProperty );
      }
      set
      {
        this.SetValue( DataGridControl.DefaultGroupConfigurationProperty, value );
      }
    }

    private static void OnDefaultGroupConfigurationChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e )
    {
      DataGridControl dataGridControl = ( DataGridControl )sender;
      dataGridControl.RefreshData( true );
    }

    #endregion

    #region DefaultHeadersFooters Property

    public static readonly DependencyProperty DefaultHeadersFootersProperty = DependencyProperty.Register(
      "DefaultHeadersFooters",
      typeof( HeaderFooterTypes ),
      typeof( DataGridControl ),
      new PropertyMetadata( HeaderFooterTypes.GroupByControl | HeaderFooterTypes.ColumnManagerRow, new PropertyChangedCallback( DataGridControl.OnDefaultHeadersFootersChanged ) ) );

    public HeaderFooterTypes DefaultHeadersFooters
    {
      get
      {
        return ( HeaderFooterTypes )this.GetValue( DataGridControl.DefaultHeadersFootersProperty );
      }
      set
      {
        this.SetValue( DataGridControl.DefaultHeadersFootersProperty, value );
      }
    }

    private static void OnDefaultHeadersFootersChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e )
    {
      var dataGridControl = ( DataGridControl )sender;
      dataGridControl.RefreshDefaultHeadersFooters();
    }

    #endregion // DefaultHeaders Property

    #region Filter Event

    public event EventHandler<DataGridFilterEventArgs> Filter
    {
      add
      {
        // Disable filtering in design mode.
        if( this.DataGridContext.DataSource == null )
          return;

        // Only keep the latest handler.
        m_currentFilter = this.GeneratePredicateForFilter( value );
        this.DataGridContext.DataSource.Filter = m_currentFilter;
      }
      remove
      {
        // Disable filtering in design mode.
        if( this.DataGridContext.DataSource == null )
          return;

        //In the case of a remove, just clear the Filter. 
        this.DataGridContext.DataSource.Filter = null;
        m_currentFilter = null;
      }
    }

    private Predicate<object> GeneratePredicateForFilter( EventHandler<DataGridFilterEventArgs> handler )
    {
      if( handler == null )
        return null;

      return new Predicate<object>( ( item ) =>
      {
        Debug.Assert( !( item is DataItem ), "A DataItem was the item passed as a parameter." );

        DataGridFilterEventArgs eventArgs = new DataGridFilterEventArgs( item );

        handler.Invoke( this, eventArgs );

        return eventArgs.Accepted;
      } );
    }

    #endregion

    #region FilterCellStyle Property

    public static readonly DependencyProperty FilterCellStyleProperty = DependencyProperty.Register(
      "FilterCellStyle",
      typeof( Style ),
      typeof( DataGridControl ),
      new PropertyMetadata( null, new PropertyChangedCallback( DataGridControl.OnFilterCellStyleChanged ) ) );

    public Style FilterCellStyle
    {
      get
      {
        return ( Style )this.GetValue( DataGridControl.FilterCellStyleProperty );
      }
      set
      {
        this.SetValue( DataGridControl.FilterCellStyleProperty, value );
      }
    }

    private static void OnFilterCellStyleChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e )
    {
      var dataGridControl = ( DataGridControl )sender;
      dataGridControl.RefreshColumns( true );
    }

    #endregion // FilterCellStyle Property

    #region FilterExpression Dependency Property

    public static readonly DependencyProperty FilterExpressionProperty = DependencyProperty.Register(
      "FilterExpression",
      typeof( FilterExpressionBase ),
      typeof( DataGridControl ),
      new PropertyMetadata( null, new PropertyChangedCallback( DataGridControl.OnFilterExpressionChanged ) ) );

    public FilterExpressionBase FilterExpression
    {
      get
      {
        return ( FilterExpressionBase )this.GetValue( DataGridControl.FilterExpressionProperty );
      }
      set
      {
        this.SetValue( DataGridControl.FilterExpressionProperty, value );
      }
    }

    private static void OnFilterExpressionChanged( object sender, DependencyPropertyChangedEventArgs args )
    {
      DataGridControl dataGrid = ( DataGridControl )sender;

      dataGrid.DataGridContext.SyncProperty( () => dataGrid.DataGridContext.FilterExpression = (FilterExpressionBase)args.NewValue );
    } 

    #endregion

    #region FilterRowStyle Property

    public static readonly DependencyProperty FilterRowStyleProperty = DependencyProperty.Register(
      "FilterRowStyle",
      typeof( Style ),
      typeof( DataGridControl ),
      new PropertyMetadata( null, new PropertyChangedCallback( DataGridControl.OnFilterRowStyleChanged ) ) );

    public Style FilterRowStyle
    {
      get
      {
        return ( Style )this.GetValue( DataGridControl.FilterRowStyleProperty );
      }
      set
      {
        this.SetValue( DataGridControl.FilterRowStyleProperty, value );
      }
    }

    private static void OnFilterRowStyleChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e )
    {
    }

    #endregion // FilterRowStyle Property

    #region InsertionCellStyle Property

    public static readonly DependencyProperty InsertionCellStyleProperty = DependencyProperty.Register(
      "InsertionCellStyle",
      typeof( Style ),
      typeof( DataGridControl ),
      new PropertyMetadata( null, new PropertyChangedCallback( DataGridControl.OnInsertionCellStyleChanged ) ) );

    public Style InsertionCellStyle
    {
      get
      {
        return ( Style )this.GetValue( DataGridControl.InsertionCellStyleProperty );
      }
      set
      {
        this.SetValue( DataGridControl.InsertionCellStyleProperty, value );
      }
    }

    private static void OnInsertionCellStyleChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e )
    {
      var dataGridControl = ( DataGridControl )sender;
      dataGridControl.RefreshColumns( true );
    }

    #endregion // InsertionCellStyle Property

    #region InsertionRowStyle Property

    public static readonly DependencyProperty InsertionRowStyleProperty = DependencyProperty.Register(
      "InsertionRowStyle",
      typeof( Style ),
      typeof( DataGridControl ),
      new PropertyMetadata( null, new PropertyChangedCallback( DataGridControl.OnInsertionRowStyleChanged ) ) );

    public Style InsertionRowStyle
    {
      get
      {
        return ( Style )this.GetValue( DataGridControl.InsertionRowStyleProperty );
      }
      set
      {
        this.SetValue( DataGridControl.InsertionRowStyleProperty, value );
      }
    }

    private static void OnInsertionRowStyleChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e )
    {
    }

    #endregion // InsertionRowStyle Property

    #region FixedHeaders Property

    public Collection<UIElement> FixedHeaders
    {
      get
      {
        return m_fixedHeaders;
      }
    }

    #endregion

    #region FixedFooters Property

    public Collection<UIElement> FixedFooters
    {
      get
      {
        return m_fixedFooters;
      }
    }

    #endregion

    #region GroupByControlStyle Property

    public static readonly DependencyProperty GroupByControlStyleProperty = DependencyProperty.Register(
      "GroupByControlStyle",
      typeof( Style ),
      typeof( DataGridControl ),
      new PropertyMetadata( null, new PropertyChangedCallback( DataGridControl.OnGroupByControlStyleChanged ) ) );

    public Style GroupByControlStyle
    {
      get
      {
        return ( Style )this.GetValue( DataGridControl.GroupByControlStyleProperty );
      }
      set
      {
        this.SetValue( DataGridControl.GroupByControlStyleProperty, value );
      }
    }

    private static void OnGroupByControlStyleChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e )
    {
    }

    #endregion // GroupByControlStyle Property

    #region GroupByItemStyle Property

    public static readonly DependencyProperty GroupByItemStyleProperty = DependencyProperty.Register(
      "GroupByItemStyle",
      typeof( Style ),
      typeof( DataGridControl ),
      new PropertyMetadata( null, new PropertyChangedCallback( DataGridControl.OnGroupByItemStyleChanged ) ) );

    public Style GroupByItemStyle
    {
      get
      {
        return ( Style )this.GetValue( DataGridControl.GroupByItemStyleProperty );
      }
      set
      {
        this.SetValue( DataGridControl.GroupByItemStyleProperty, value );
      }
    }

    private static void OnGroupByItemStyleChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e )
    {
    }

    #endregion // GroupByItemStyle Property

    #region GroupConfigurationSelector Property

    public static readonly DependencyProperty GroupConfigurationSelectorProperty = DependencyProperty.Register(
      "GroupConfigurationSelector",
      typeof( DataGridGroupConfigurationSelector ),
      typeof( DataGridControl ),
      new PropertyMetadata( ( DataGridGroupConfigurationSelector )null, new PropertyChangedCallback( DataGridControl.OnGroupConfigurationSelectorChanged ) ) );

    public DataGridGroupConfigurationSelector GroupConfigurationSelector
    {
      get
      {
        return ( DataGridGroupConfigurationSelector )this.GetValue( DataGridControl.GroupConfigurationSelectorProperty );
      }
      set
      {
        this.SetValue( DataGridControl.GroupConfigurationSelectorProperty, value );
      }
    }

    private static void OnGroupConfigurationSelectorChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e )
    {
      DataGridControl dataGridControl = ( DataGridControl )sender;
      dataGridControl.RefreshData( true );
    }

    #endregion

    #region GroupContext Attached Dependency Property

    public static readonly DependencyProperty GroupContextProperty = DependencyProperty.RegisterAttached(
      "GroupContext",
      typeof( GroupContext ),
      typeof( DataGridControl ),
      new PropertyMetadata( null )
    );

    public static void SetGroupContext( DependencyObject element, GroupContext value )
    {
      element.SetValue( GroupContextProperty, value );
    }

    public static GroupContext GetGroupContext( DependencyObject element )
    {
      return ( GroupContext )element.GetValue( GroupContextProperty );
    }

    #endregion GroupContext Attached Dependency Property

    #region GroupDescriptions Property

    public ObservableCollection<GroupDescription> GroupDescriptions
    {
      get
      {
        return this.DataGridContext.GroupDescriptions;
      }
    }

    #endregion

    #region GroupNavigationModes Property

    public static readonly DependencyProperty GroupNavigationModesProperty = DependencyProperty.Register(
      "GroupNavigationModes",
      typeof( GroupNavigationModes ),
      typeof( DataGridControl ),
      new PropertyMetadata( GroupNavigationModes.All, new PropertyChangedCallback( DataGridControl.OnGroupNavigationModesChanged ) ) );

    public GroupNavigationModes GroupNavigationModes
    {
      get
      {
        return ( GroupNavigationModes )this.GetValue( DataGridControl.GroupNavigationModesProperty );
      }
      set
      {
        this.SetValue( DataGridControl.GroupNavigationModesProperty, value );
      }
    }

    private static void OnGroupNavigationModesChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e )
    {
      var dataGridControl = ( DataGridControl )sender;
      dataGridControl.UpdateAllGroupContainerNavigationToolsVisibility();
      dataGridControl.RaisePropertyChanged( DataGridControl.GroupNavigationModesPropertyName );
    }

    #endregion // GroupNavigationModes Property

    #region HorizontalScrollBarVisibility Property

    public static readonly DependencyProperty HorizontalScrollBarVisibilityProperty = DependencyProperty.Register(
      "HorizontalScrollBarVisibility",
      typeof( ScrollBarVisibility ),
      typeof( DataGridControl ),
      new PropertyMetadata( ( ScrollBarVisibility )ScrollBarVisibility.Auto,
                            new PropertyChangedCallback( DataGridControl.OnHorizontalScrollBarVisibilityChanged ) ) );

    public ScrollBarVisibility HorizontalScrollBarVisibility
    {
      get
      {
        return ( ScrollBarVisibility )this.GetValue( DataGridControl.HorizontalScrollBarVisibilityProperty );
      }
      set
      {
        this.SetValue( DataGridControl.HorizontalScrollBarVisibilityProperty, value );
      }
    }

    private static void OnHorizontalScrollBarVisibilityChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e )
    {
      DataGridControl dataGridControl = sender as DataGridControl;
      if( e.OldValue != e.NewValue )
      {
        dataGridControl.UpdateHorizontalScrollBarVisibility();
      }
    }

    #endregion

    #region IsInitializing Property (Private)

    private bool IsInitializing
    {
      get
      {
        return ( m_initializationCount != 0 );
      }
    }

    #endregion

    public static readonly DependencyProperty ItemScrollingBehaviorProperty = DependencyProperty.Register(
     "ItemScrollingBehavior",
     typeof( ItemScrollingBehavior ),
     typeof( DataGridControl ),
     new PropertyMetadata( ItemScrollingBehavior.Immediate, null ) );

    public ItemScrollingBehavior ItemScrollingBehavior
    {
      get
      {
        return ( ItemScrollingBehavior )this.GetValue( DataGridControl.ItemScrollingBehaviorProperty );
      }
      set
      {
        this.SetValue( DataGridControl.ItemScrollingBehaviorProperty, value );
      }
    }

    #region ItemsSource Property

    public static readonly DependencyProperty ItemsSourceProperty = DependencyProperty.Register(
      "ItemsSource",
      typeof( object ),
      typeof( DataGridControl ),
      new PropertyMetadata( null, new PropertyChangedCallback( DataGridControl.OnItemsSourceChanged ) ) );

    public object ItemsSource
    {
      get
      {
        return ( object )this.GetValue( DataGridControl.ItemsSourceProperty );
      }
      set
      {
        this.SetValue( DataGridControl.ItemsSourceProperty, value );
      }
    }

    private static void OnItemsSourceChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e )
    {
      DataGridControl dataGridControl = sender as DataGridControl;

      if( dataGridControl == null )
        return;

      dataGridControl.OnItemsSourceChanged( e.NewValue );
    }

    #endregion

    #region LeftFixedColumnCount Property

    public static readonly DependencyProperty LeftFixedColumnCountProperty = DependencyProperty.Register(
      "LeftFixedColumnCount",
      typeof( int ),
      typeof( DataGridControl ),
      new PropertyMetadata( 0, new PropertyChangedCallback( DataGridControl.OnLeftFixedColumnCountChanged ) ) );

    public int LeftFixedColumnCount
    {
      get
      {
        return ( int )this.GetValue( DataGridControl.LeftFixedColumnCountProperty );
      }
      set
      {
        this.SetValue( DataGridControl.LeftFixedColumnCountProperty, value );
      }
    }

    private static void OnLeftFixedColumnCountChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e )
    {
      DataGridControl datagrid = ( DataGridControl )sender;
      if( datagrid.LeftFixedColumnCount < 0 )
        throw new ArgumentOutOfRangeException( "LeftFixedColumnCount", "LeftFixedColumnCount must be greater than or equal to zero." );

      datagrid.RefreshColumns( false );
    }

    #endregion // LeftFixedColumnCount Property

    #region RightFixedColumnCount Property

    public static readonly DependencyProperty RightFixedColumnCountProperty = DependencyProperty.Register(
      "RightFixedColumnCount",
      typeof( int ),
      typeof( DataGridControl ),
      new PropertyMetadata( 0, new PropertyChangedCallback( DataGridControl.OnRightFixedColumnCountChanged ) ) );

    public int RightFixedColumnCount
    {
      get
      {
        return ( int )this.GetValue( DataGridControl.RightFixedColumnCountProperty );
      }
      set
      {
        this.SetValue( DataGridControl.RightFixedColumnCountProperty, value );
      }
    }

    private static void OnRightFixedColumnCountChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e )
    {
      DataGridControl datagrid = ( DataGridControl )sender;
      if( datagrid.RightFixedColumnCount < 0 )
        throw new ArgumentOutOfRangeException( "RightFixedColumnCount", "RightFixedColumnCount must be greater than or equal to zero." );

      datagrid.RefreshColumns( false );
    }

    #endregion // RightFixedColumnCount Property

    #region MaxColumnWidth Property

    public static readonly DependencyProperty MaxColumnWidthProperty = DependencyProperty.Register(
      "MaxColumnWidth",
      typeof( double ),
      typeof( DataGridControl ),
      new PropertyMetadata( Double.PositiveInfinity, new PropertyChangedCallback( DataGridControl.OnMaxColumnWidthChanged ) ) );

    public double MaxColumnWidth
    {
      get
      {
        return ( double )this.GetValue( DataGridControl.MaxColumnWidthProperty );
      }
      set
      {
        this.SetValue( DataGridControl.MaxColumnWidthProperty, value );
      }
    }

    private static void OnMaxColumnWidthChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e )
    {
      var dataGridControl = ( DataGridControl )sender;

      var oldMaxWidth = ( double )e.OldValue;
      var newMaxWidth = ( double )e.NewValue;

      if( newMaxWidth < 0d )
      {
        throw new ArgumentOutOfRangeException( "MaxWidth", "MaxWidth must be greater than or equal to zero." );
      }

      dataGridControl.UpdateColumnsWidth();
    }

    #endregion // MaxColumnWidth Property

    #region MinColumnWidth Property

    public static readonly DependencyProperty MinColumnWidthProperty = DependencyProperty.Register(
      "MinColumnWidth",
      typeof( double ),
      typeof( DataGridControl ),
      new PropertyMetadata( 0d, new PropertyChangedCallback( DataGridControl.OnMinColumnWidthChanged ) ) );

    public double MinColumnWidth
    {
      get
      {
        return ( double )this.GetValue( DataGridControl.MinColumnWidthProperty );
      }
      set
      {
        this.SetValue( DataGridControl.MinColumnWidthProperty, value );
      }
    }

    private static void OnMinColumnWidthChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e )
    {
      var dataGridControl = ( DataGridControl )sender;

      var oldMinWidth = ( double )e.OldValue;
      var newMinWidth = ( double )e.NewValue;

      if( newMinWidth < 0d )
      {
        throw new ArgumentOutOfRangeException( "MinWidth", "MinWidth must be greater than or equal to zero." );
      }
      else if( Double.IsPositiveInfinity( newMinWidth ) )
      {
        throw new ArgumentOutOfRangeException( "MinWidth", "MinWidth must be less than positive infinity." );
      }

      dataGridControl.UpdateColumnsWidth();
    }

    #endregion // MinColumnWidth Property

    #region NotificationReceived Event

    public event EventHandler<NotificationReceivedEventArgs> NotificationReceived;

    internal void RaiseNotificationReceived( NotificationReceivedEventArgs e )
    {
      if( this.NotificationReceived != null )
      {
        this.NotificationReceived( this, e );
      }
    }

    #endregion // NotificationReceived Event

    #region ReadOnly Property

    public static readonly DependencyProperty ReadOnlyProperty = DependencyProperty.Register(
      "ReadOnly",
      typeof( bool ),
      typeof( DataGridControl ),
      new PropertyMetadata( false, new PropertyChangedCallback( DataGridControl.OnReadOnlyChanged ) ) );

    public bool ReadOnly
    {
      get
      {
        return ( bool )this.GetValue( DataGridControl.ReadOnlyProperty );
      }
      set
      {
        this.SetValue( DataGridControl.ReadOnlyProperty, value );
      }
    }

    private static void OnReadOnlyChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e )
    {
      var dataGrid = ( DataGridControl )sender;

      // If the grid becomes read only, cancel the edit process on each row being edited.
      if( dataGrid.ReadOnly )
      {
        dataGrid.CancelEdit();
      }

      var inspector = CellEditorVisibilityInspector.Create( dataGrid ).Check();
      dataGrid.UpdateCellsEditorVisibility( inspector );
    }

    #endregion

    #region RowBackground Property

    public static readonly DependencyProperty RowBackgroundProperty = DependencyProperty.Register(
      "RowBackground",
      typeof( Brush ),
      typeof( DataGridControl ),
      new PropertyMetadata( null, new PropertyChangedCallback( DataGridControl.OnRowBackgroundChanged ) ) );

    public Brush RowBackground
    {
      get
      {
        return ( Brush )this.GetValue( DataGridControl.RowBackgroundProperty );
      }
      set
      {
        this.SetValue( DataGridControl.RowBackgroundProperty, value );
      }
    }

    private static void OnRowBackgroundChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e )
    {
      var dataGridControl = ( DataGridControl )sender;
      dataGridControl.OnRowsBackgroundChange( dataGridControl.RowBackground );
    }

    #endregion // RowBackground Property

    #region RowHeight Property

    public static readonly DependencyProperty RowHeightProperty = DependencyProperty.Register(
      "RowHeight",
      typeof( double ),
      typeof( DataGridControl ),
      new PropertyMetadata( 24d, new PropertyChangedCallback( DataGridControl.OnRowHeightChanged ) ) );

    public double RowHeight
    {
      get
      {
        return ( double )this.GetValue( DataGridControl.RowHeightProperty );
      }
      set
      {
        this.SetValue( DataGridControl.RowHeightProperty, value );
      }
    }

    private static void OnRowHeightChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e )
    {
      var dataGridControl = ( DataGridControl )sender;
      if( dataGridControl.RowHeight <= 0 || double.IsNaN( dataGridControl.RowHeight ) )
        throw new ArgumentOutOfRangeException( "RowHeight", "RowHeight must be greater than 0." );

      dataGridControl.RefreshData( true );
    }

    #endregion // RowHeight Property

    #region RowStyle Property

    public static readonly DependencyProperty RowStyleProperty = DependencyProperty.Register(
      "RowStyle",
      typeof( Style ),
      typeof( DataGridControl ),
      new PropertyMetadata( null, new PropertyChangedCallback( DataGridControl.OnRowStyleChanged ) ) );

    public Style RowStyle
    {
      get
      {
        return ( Style )this.GetValue( DataGridControl.RowStyleProperty );
      }
      set
      {
        this.SetValue( DataGridControl.RowStyleProperty, value );
      }
    }

    private static void OnRowStyleChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e )
    {
      var dataGridControl = ( DataGridControl )sender;
      dataGridControl.RefreshData( true );
    }

    #endregion // RowStyle Property

    #region SelectedItem Dependency Property

    public static readonly DependencyProperty SelectedItemProperty = DependencyProperty.Register(
      "SelectedItem",
      typeof( object ),
      typeof( DataGridControl ),
      new PropertyMetadata( null, new PropertyChangedCallback( DataGridControl.OnSelectedItemChanged ) ) );
    public object SelectedItem
    {
      get
      {
        return ( object )this.GetValue( DataGridControl.SelectedItemProperty );
      }
      set
      {
        this.SetValue( DataGridControl.SelectedItemProperty, value );
      }
    }

    private static void OnSelectedItemChanged( object sender, DependencyPropertyChangedEventArgs args )
    {
      DataGridControl dataGridControl = ( DataGridControl )sender;

      if( dataGridControl.IsDataSourceAsynchronous )
      {
        throw new InvalidOperationException( "The SelectedItem property can only be used with a synchronous data source." );
      }

      if( dataGridControl.DataGridContext.DataSource.IsPrimaryKeyVolatile && !dataGridControl.m_internalSetSelectedItem )
        throw new InvalidOperationException( "Cannot set a selected item with the current data source. Use CurrentPath instead." );

      dataGridControl.DataGridContext.SyncProperty( () => dataGridControl.DataGridContext.SelectedItem = args.NewValue );

      if( !dataGridControl.m_internalSetSelectedItem )
      {
        dataGridControl.ExternalSetSelectedItem( args );
      }
    }

    #endregion

    #region SelectedItems Property

    public SelectedItemCollection SelectedItems
    {
      get
      {
        return this.DataGridContext.SelectedItems;
      }
    }

    #endregion

    #region SelectedRanges Property

    public IList<SelectionRange> SelectedRanges
    {
      get
      {
        return this.DataGridContext.SelectedRanges;
      }
    }

    #endregion

    #region SelectionMode Property

    public static readonly DependencyProperty SelectionModeProperty = DependencyProperty.Register(
      "SelectionMode",
      typeof( SelectionMode ),
      typeof( DataGridControl ),
      new PropertyMetadata( ( SelectionMode )SelectionMode.Extended, null ) );

    public SelectionMode SelectionMode
    {
      get
      {
        return ( SelectionMode )this.GetValue( DataGridControl.SelectionModeProperty );
      }
      set
      {
        this.SetValue( DataGridControl.SelectionModeProperty, value );
      }
    }

    #endregion

    #region SortDescriptions Property

    public SortDescriptionCollection SortDescriptions
    {
      get
      {
        return this.DataGridContext.SortDescriptions;
      }
    }

    #endregion

    #region StatContext Attached Dependency Property

    public static readonly DependencyProperty StatContextProperty = DependencyProperty.RegisterAttached(
      "StatContext",
      typeof( StatContext ),
      typeof( DataGridControl ),
      new PropertyMetadata( null )
    );

    public static void SetStatContext( DependencyObject element, StatContext value )
    {
      element.SetValue( StatContextProperty, value );
    }

    public static StatContext GetStatContext( DependencyObject element )
    {
      return ( StatContext )element.GetValue( StatContextProperty );
    }

    #endregion StatContext Attached Dependency Property

    #region StatFunctions Property

    public StatFunctionCollection StatFunctions
    {
      get
      {
        return m_statFunctions;
      }
    }

    private StatFunctionCollection m_statFunctions = new StatFunctionCollection();

    #endregion

    #region FixedColumnToggleButtonVisibility Property

    public static readonly DependencyProperty FixedColumnToggleButtonVisibilityProperty;

    public FixedColumnToggleButtonVisibility FixedColumnToggleButtonVisibility
    {
      get
      {
        return ( FixedColumnToggleButtonVisibility )this.GetValue( DataGridControl.FixedColumnToggleButtonVisibilityProperty );
      }
      set
      {
        this.SetValue( DataGridControl.FixedColumnToggleButtonVisibilityProperty, value );
      }
    }

    private static void OnFixedColumnToggleButtonVisibilityChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e )
    {
      DataGridControl datagridControl = ( DataGridControl )sender;
      datagridControl.RefreshFixedColumnToggleButtonVisibility();
    }

    #endregion // FixedColumnToggleButtonVisibility Property

    #region UseDefaultHeadersFooters Property

    public static readonly DependencyProperty UseDefaultHeadersFootersProperty = DependencyProperty.Register(
      "UseDefaultHeadersFooters",
      typeof( bool ),
      typeof( DataGridControl ),
      new PropertyMetadata( true, new PropertyChangedCallback( DataGridControl.OnUseDefaultHeadersFootersChanged ) ) );

    public bool UseDefaultHeadersFooters
    {
      get
      {
        return ( bool )this.GetValue( UseDefaultHeadersFootersProperty );
      }
      set
      {
        this.SetValue( UseDefaultHeadersFootersProperty, value );
      }
    }

    private static void OnUseDefaultHeadersFootersChanged( object sender, DependencyPropertyChangedEventArgs e )
    {
      var dataGridControl = ( DataGridControl )sender;
      dataGridControl.RefreshDefaultHeadersFooters();
    }

    #endregion // UseDefaultHeadersFooters Property

    #region VerticalScrollBarVisibility Property

    public static readonly DependencyProperty VerticalScrollBarVisibilityProperty = DependencyProperty.Register(
      "VerticalScrollBarVisibility",
      typeof( ScrollBarVisibility ),
      typeof( DataGridControl ),
      new PropertyMetadata( ( ScrollBarVisibility )ScrollBarVisibility.Visible,
                            new PropertyChangedCallback( DataGridControl.OnVerticalScrollBarVisibilityChanged ) ) );

    public ScrollBarVisibility VerticalScrollBarVisibility
    {
      get
      {
        return ( ScrollBarVisibility )this.GetValue( DataGridControl.VerticalScrollBarVisibilityProperty );
      }
      set
      {
        this.SetValue( DataGridControl.VerticalScrollBarVisibilityProperty, value );
      }
    }

    private static void OnVerticalScrollBarVisibilityChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e )
    {
      DataGridControl dataGridControl = sender as DataGridControl;
      if( e.OldValue != e.NewValue )
      {
        dataGridControl.UpdateVerticalScrollBarVisibility();
      }
    }

    #endregion

    #region Columns Property

    public ColumnCollection Columns
    {
      get
      {
        return this.DataGridContext.Columns;
      }
    }

    #endregion

    #region UnhandledDataException Event

    public event EventHandler<UnhandledDataExceptionEventArgs> UnhandledDataException;

    private void OnUnhandledDataException( UnhandledDataExceptionEventArgs e )
    {
      if( this.UnhandledDataException != null )
      {
        this.UnhandledDataException( this, e );
      }
    }

    #endregion

    public event EventHandler SelectionChanged;

    #region ScrollToTopCommand Property

    internal static readonly DependencyProperty ScrollToTopCommandProperty = DependencyProperty.Register(
      "ScrollToTopCommand",
      typeof( ICommand ),
      typeof( DataGridControl ),
      new PropertyMetadata( null ) );

    public ICommand ScrollToTopCommand
    {
      get
      {
        return ( ICommand )this.GetValue( DataGridControl.ScrollToTopCommandProperty );
      }
      private set
      {
        this.SetValue( DataGridControl.ScrollToTopCommandProperty, value );
      }
    }

    #endregion

    #region ScrollToBottomCommand Property

    internal static readonly DependencyProperty ScrollToBottomCommandProperty = DependencyProperty.Register(
      "ScrollToBottomCommand",
      typeof( ICommand ),
      typeof( DataGridControl ),
      new PropertyMetadata( null ) );

    public ICommand ScrollToBottomCommand
    {
      get
      {
        return ( ICommand )this.GetValue( DataGridControl.ScrollToBottomCommandProperty );
      }
      private set
      {
        this.SetValue( DataGridControl.ScrollToBottomCommandProperty, value );
      }
    }

    #endregion

    #region IsDataSourceAsynchronous Property (Internal)

    internal bool IsDataSourceAsynchronous
    {
      get
      {
        if( this.DataGridContext.DataSource == null )
          throw new InvalidOperationException( "The data source cannot be null when querying it to know if it is asynchronous." );

        if( this.DataGridContext.DataSource.Provider == null )
          throw new InvalidOperationException( "The data-source provider cannot be null when querying it to know if it is asynchronous." );

        return this.DataGridContext.DataSource.Provider.IsAsynchronous;
      }
    }

    #endregion //IsDataSourceAsynchronous Property

    #region VisualState Property (Internal)

    internal VisualStateHelper VisualStateHelper
    {
      get;
      private set;
    }

    #endregion

    #region IsDefaultHeaderFooter Attached Property (Private)

    private static readonly DependencyProperty IsDefaultHeaderFooterProperty = DependencyProperty.RegisterAttached(
      "IsDefaultHeaderFooter",
      typeof( bool ),
      typeof( DataGridControl ),
      new PropertyMetadata( false ) );

    private static bool GetIsDefaultHeaderFooter( DependencyObject obj )
    {
      return ( bool )obj.GetValue( DataGridControl.IsDefaultHeaderFooterProperty );
    }

    private static void SetIsDefaultHeaderFooter( DependencyObject obj, bool value )
    {
      obj.SetValue( DataGridControl.IsDefaultHeaderFooterProperty, value );
    }

    #endregion // DefaultHeaderFooterType Attached Property (Private)

    #region DataGridPanel Property (private)

    internal DataGridPanel DataGridPanel
    {
      get;
      private set;
    }

    #endregion DataGridPanel Property (private)

    #region CurrentElement Property (private)

    private UIElement CurrentElement
    {
      get
      {
        if( this.CurrentPath == null )
          return null;

        return this.GetContainerFromPath( this.CurrentDataPath );
      }
    }

    #endregion

    #region CurrentCell Property (private)

    private Cell CurrentCell
    {
      get
      {
        if( this.CurrentColumn == null )
          return null;

        Row currentRow = this.CurrentElement as Row;
        Cell currentCell = null;

        if( currentRow != null )
        {
          currentCell = currentRow.RenderedCells
            .FirstOrDefault( ( c ) => object.Equals( c.ParentColumn, this.CurrentColumn ) );
        }

        return currentCell;
      }
    }

    public event EventHandler CurrentCellChanged;

    private void RaiseCurrentCellChanged()
    {
      if( this.CurrentCellChanged != null )
      {
        this.CurrentCellChanged( this, EventArgs.Empty );
      }
    }

    #endregion

    #region CurrentMouseOverRowProperty (private)

    private Row CurrentMouseOverRow
    {
      get;
      set;
    }

    #endregion

    #region CurrentMouseOverColumnProperty (private)

    private Column CurrentMouseOverColumn
    {
      get;
      set;
    }

    #endregion

    #region DataSource Property (private)

    internal DataGridDataSource DataSource
    {
      get
      {
        return this.DataGridContext.DataSource;
      }
    }

    #endregion

    #region DataHelper Property (private)

    private IDataSourceWrapperHelper DataHelper
    {
      get
      {
        return this.DataSource.DataHelper;
      }
    }

    #endregion

    #region RootHost Property (private)

    internal RootHost RootHost
    {
      get
      {
        return this.DataGridPanel.RootHost;
      }
    }

    #endregion

    #region RootHost Property (private)

    internal VirtualRootContainer RootContainer
    {
      get
      {
        return this.DataGridPanel.RootHost.RootContainer;
      }
    }

    #endregion

    #region RootHost Property (private)

    internal Control FocusDump
    {
      get
      {
        return this;
      }
    }

    #endregion

    #region ColumnPanel Property (private)

    private ColumnPanel ColumnPanel
    {
      get
      {
        return this.DataGridPanel.ColumnPanel;
      }
    }

    #endregion

    #region CurrentDataPath Property (private)

    private DataPath CurrentDataPath
    {
      get
      {
        return this.DataGridContext.GetActualDataPathOrDataPath( this.CurrentPath );
      }
      set
      {
        this.CurrentPath = ( value != null ) ? new DataGridPath( value ) : null;
      }
    }

    #endregion

    private struct SavedDataSourceData
    {
      internal ObservableCollection<GroupDescription> groupDescriptions;
      internal SortDescriptionCollection sortDescriptions;
    }

    public IAsyncResult BeginGetSelectedItems( AsyncCallback asyncCallback, object asyncState )
    {
      return this.DataGridContext.BeginGetSelectedItems( asyncCallback, asyncState );
    }

    public IEnumerable<object> EndGetSelectedItems( IAsyncResult asyncResult )
    {
      return this.DataGridContext.EndGetSelectedItems( asyncResult );
    }

    public void BringColumnIntoView( Column column )
    {
      //Only scroll column, without changing anything.
      this.BringItemIntoViewCore( null, column, false, false );
    }

    public void BringItemIntoView( object item )
    {
      this.BringItemIntoView( item, null, false, false );
    }

    public void BringItemIntoView( DataGridPath dataGridPath )
    {
      this.BringItemIntoView( dataGridPath, null, false, false );
    }

    public void BringItemIntoView( object item, Column column, bool updateCurrent, bool updateSelection )
    {
      if( this.DataSource == null || this.DataSource.IsPrimaryKeyVolatile )
        throw new InvalidOperationException( "Unable to bring the item into view. Either the grid is not bound to a data source or the primary keys have changed." );

      //Let's get a DataGridPath
      DataPath dataGridPath = this.DataGridContext.GetDataPathFromItem( item );

      this.BringItemIntoViewCore( dataGridPath, column, updateCurrent, updateSelection );
    }

    public void BringItemIntoView( DataGridPath dataGridPath, Column column, bool updateCurrent, bool updateSelection )
    {
      DataPath dataPath = this.DataGridContext.GetActualDataPathOrDataPath( dataGridPath );
      this.BringItemIntoViewCore( dataPath, column, updateCurrent, updateSelection );
    }

    private void BringItemIntoViewCore( DataPath dataPath, Column column, bool updateCurrent, bool updateSelection )
    {
      if( this.DataSource == null || this.DataSource.IsPrimaryKeyVolatile )
        throw new InvalidOperationException( "Unable to bring the item into view. Either the grid is not bound to a data source or the primary keys have changed." );

      if( dataPath != null )
      {
        m_rowUpdateManager.BringIntoView( dataPath, updateCurrent, updateSelection );
      }

      if( column != null )
      {
        m_columnUpdateManager.BringIntoView( column, updateCurrent, false );
      }
    }

    public UIElement GetContainerFromItem( object item )
    {
      if( this.DataSource == null || this.DataSource.IsPrimaryKeyVolatile )
        throw new InvalidOperationException( "Unable to retrieve the container from the specified item. Either the grid is not bound to a data source or the primary keys have changed." );

      DataPath path = this.DataGridContext.GetDataPathFromItem( item );

      if( path == null )
        return null;

      return this.GetContainerFromPath( path ) as UIElement;
    }

    public UIElement GetContainerFromPath( DataGridPath path )
    {
      DataPath dataPath = this.DataGridContext.GetActualDataPathOrDataPath( path );
      return this.GetContainerFromPath( dataPath ) as UIElement;
    }

    private UIElement GetContainerFromPath( DataPath path )
    {
      UIElement currentElement = null;
      DataGridElementVisitor dataGridElementVisitor = null;

      Action<IDataGridElement> action = ( e ) =>
      {
        if( object.Equals( e.Path, path ) )
        {
          currentElement = e.Visual;
          dataGridElementVisitor.StopVisit();
        }
      };

      dataGridElementVisitor = new DataGridElementVisitor( ChildrenPolicy.RenderedChildrenOnly, action );
      this.DataGridPanel.Accept( dataGridElementVisitor );

      if( currentElement == null )
      {
        VirtualContainerVisitor virtualContainerVisitor = null;
        Action<VirtualContainerBase> virtualcontaierAction = ( e ) =>
        {
          if( object.Equals( e.Path, path ) )
          {
            currentElement = ( ( WrapperBase )e.Visual ).Child;
            virtualContainerVisitor.StopVisit();
          }
        };

        virtualContainerVisitor = new VirtualContainerVisitor( ChildrenPolicy.RenderedChildrenOnly, virtualcontaierAction );
        this.DataGridPanel.Accept( virtualContainerVisitor );
      }

      return currentElement;
    }

    public DataGridPath GetPathFromItem( object item )
    {
      return this.DataGridContext.GetPathFromItem( item );
    }

    public DataGridPath GetPathFromContainer( UIElement container )
    {
      if( container is IDataGridElement )
      {
        DataPath path = ( ( IDataGridElement )container ).Path;
        return path.IsStubPath() ? null : new DataGridPath( path );
      }

      throw new ArgumentException( "The specified container is not a valid element.", "container" );
    }

    public override void OnApplyTemplate()
    {
      if( m_dataGridPanelHost != null )
      {
        m_dataGridPanelHost.Child = null;
      }

      if( m_verticalScrollBar != null )
      {
        m_verticalScrollBar.Scroll -= this.OnVerticalScroll;
      }

      if( m_horizontalScrollBar != null )
      {
        m_horizontalScrollBar.Scroll -= this.OnHorizontalScroll;
      }

      m_dataGridPanelHost = this.GetTemplateChild( "dataGridPanelHost" ) as Border;
      m_verticalScrollBar = this.GetTemplateChild( "VerticalScrollBar" ) as ScrollBar;
      m_horizontalScrollBar = this.GetTemplateChild( "HorizontalScrollBar" ) as ScrollBar;

      if( m_dataGridPanelHost != null )
      {
        m_dataGridPanelHost.Child = this.DataGridPanel;
      }

      if( m_verticalScrollBar != null )
      {
        m_verticalScrollBar.SmallChange = 0.0001d;
        m_verticalScrollBar.LargeChange = 0.0001d;
        m_verticalScrollBar.Scroll += this.OnVerticalScroll;
      }

      if( m_horizontalScrollBar != null )
      {
        m_horizontalScrollBar.SmallChange = 0.0001d;
        m_horizontalScrollBar.LargeChange = 0.0001d;
        m_horizontalScrollBar.Scroll += this.OnHorizontalScroll;
      }

      this.VisualStateHelper.ApplyVisualStates();

      base.OnApplyTemplate();
    }

    public bool IsGroupExpanded( DataGridPath groupPath )
    {
      return this.DataGridContext.IsGroupExpanded( groupPath );
    }

    public void ToggleGroupExpansion( DataGridPath groupPath )
    {
      this.DataGridContext.ToggleGroupExpansion( groupPath );
    }

    public void ExpandGroup( DataGridPath groupPath )
    {
      this.DataGridContext.ExpandGroup( groupPath );
    }

    public void CollapseGroup( DataGridPath groupPath )
    {
      this.DataGridContext.CollapseGroup( groupPath );
    }

    public IDisposable DeferRefresh()
    {
      return new DeferUpdateHelper( this );
    }

    protected override void OnMouseLeftButtonDown( MouseButtonEventArgs e )
    {
      this.Focus();
    }

    protected override void OnGotFocus( RoutedEventArgs e )
    {
      base.OnGotFocus( e );

      DependencyObject source = ( DependencyObject )e.OriginalSource;
      IColumnElement columnElement = ( IColumnElement )source.GetElementOrParentBase<IColumnElement>();
      DataPath elementPath = null;

      if( elementPath == null )
      {
        IDataGridElement dataGridElement = ( IDataGridElement )source.GetElementOrParentBase<IDataGridElement>();
        if( dataGridElement != null )
        {
          elementPath = dataGridElement.Path;
        }
      }

      if( elementPath == null )
      {
        GroupHeaderControl groupHeaderControl = source.GetElementOrParentBase<ControlBase>() as GroupHeaderControl;
        if( groupHeaderControl != null )
        {
          elementPath = groupHeaderControl.GroupPath;
        }
      }

      if( elementPath != null
        && elementPath.IsStubPath() )
        this.FocusDump.Focus();

      this.SetCurrentElement( elementPath, columnElement );
    }

    private object SetCurrentElement( DataPath newPath, IColumnElement columnElement )
    {
      if( ( newPath == null ) && ( columnElement == null ) )
        return null;

      DataPath oldPath = this.CurrentDataPath;
      bool setNewPath = !object.Equals( newPath, oldPath );
      bool setNewColumn = false;
      Column oldColumn = this.CurrentColumn;
      Column newColumn = null;

      if( columnElement != null )
      {
        var columnContainer = columnElement.ParentColumnContainer;
        if( columnContainer != null )
        {
          newColumn = columnContainer.Column;
        }

        setNewColumn = true;
      }

      return this.UpdateCurrentInternal( setNewPath, oldPath, newPath, setNewColumn, oldColumn, newColumn );
    }

    internal IList<UIElement> GetFixedHeaders()
    {
      return this.FixedHeaders;
    }

    internal IList<UIElement> GetFixedFooters()
    {
      return this.FixedFooters;
    }

    internal IList<HeaderFooterWrapper> GetFixedHeaders( DataPath groupPath, List<DataGridGroupConfiguration> groupConfigList )
    {
      IList<HeaderFooterWrapper> headers = this.GetGroupFixedElements( groupPath, groupConfigList.First().FixedHeaders, true );

      object defaultHeaderKey = HeaderFooterWrapper.CreateKey( DataGridControl.GroupHeaderControlKey, 0, true );
      headers.Insert( 0, new HeaderFooterWrapper( new GroupHeaderControl(), defaultHeaderKey ) );

      return headers;
    }

    internal IList<HeaderFooterWrapper> GetFixedFooters( DataPath groupPath, List<DataGridGroupConfiguration> groupConfigList )
    {
      return this.GetGroupFixedElements( groupPath, groupConfigList.First().FixedFooters, false );
    }

    internal string ResolveRowCommonState( bool isSelected, bool isMouseOver, bool isAlternate )
    {
      if( isSelected && isMouseOver )
      {
        return DataRow.CommonStateMouseOverSelected;
      }
      else if( isMouseOver && isAlternate && this.AreAlternateStatesEnabled )
      {
        return DataRow.CommonStateAlternateMouseOver;
      }
      else if( isMouseOver )
      {
        return DataRow.CommonStateMouseOver;
      }
      else if( isSelected )
      {
        return DataRow.CommonStateSelected;
      }
      else if( isAlternate && this.AreAlternateStatesEnabled )
      {
        return DataRow.CommonStateAlternate;
      }
      else
      {
        return DataRow.CommonStateNormal;
      }
    }

    internal void StartFetchingData( bool isFetching )
    {
      this.VisualStateHelper.GoToRequestPendingState( isFetching
                                                      ? DataGridControl.RequestPendingStatePending
                                                      : DataGridControl.RequestPendingStateNotPending, true );
    }

    private IList<HeaderFooterWrapper> GetGroupFixedElements( DataPath groupPath, IList<DataTemplate> fixedCollection, bool isHeaders )
    {
      List<HeaderFooterWrapper> fixedElements = new List<HeaderFooterWrapper>();

      LocationState locationState = ( isHeaders ) ? LocationState.GroupHeader : LocationState.GroupFooter;
      for( int i = 0; i < fixedCollection.Count; i++ )
      {
        DataTemplate currentTemplate = fixedCollection[ i ];
        object headerKey = HeaderFooterWrapper.CreateKey( currentTemplate, i, isHeaders );
        HeaderFooterWrapper element = new HeaderFooterWrapper( ( UIElement )currentTemplate.LoadContent(), headerKey );
        this.PrepareGroupHeaderFooterInternalCore( element, locationState, groupPath );
        fixedElements.Add( element );
      }

      return fixedElements;
    }

    private void OnDataGridLoaded( object sender, RoutedEventArgs e )
    {
      this.ScrollToTopCommand = new DataGridCommand( new Action<object>( this.OnScrollToTopExecute ), new Func<object, bool>( this.OnScrollToTopCanExecute ) );
      this.ScrollToBottomCommand = new DataGridCommand( new Action<object>( this.OnScrollToBottomExecute ), new Func<object, bool>( this.OnScrollToBottomCanExecute ) );
    }

    private void OnDataGridUnLoaded( object sender, RoutedEventArgs e )
    {
      this.ScrollToTopCommand = null;
      this.ScrollToBottomCommand = null;
    }

    private bool OnScrollToTopCanExecute( object parameter )
    {
      // We cannot scroll to the top page if no data source has been set.
      return ( this.DataGridContext.DataSource != null );
    }

    private bool OnScrollToBottomCanExecute( object parameter )
    {
      // We cannot scroll to the last page if no data source has been set.
      return ( this.DataGridContext.DataSource != null );
    }

    private void OnScrollToTopExecute( object parameter )
    {
      this.SetData( new ScrollUpdateRequest( true, ScrollEventType.First ) );

      //No need to do anything if it fails, since it will fail only if the source is empty, or if already on the top page.
    }

    private void OnScrollToBottomExecute( object parameter )
    {
      this.SetData( new ScrollUpdateRequest( true, ScrollEventType.Last ) );

      //No need to do anything if it fails, since it will fail only if the source is empty, or if already on the last page.
    }

    private void OnMouseEnterRow( object sender, XceedRoutedEventArgs args )
    {
      var row = args.OriginalSource as Row;
      if( row == null )
        return;

      this.CurrentMouseOverRow = row;

      var editableRow = row as EditableRow;
      if( editableRow != null )
      {
        var inspector = CellEditorVisibilityInspector.Create( this ).Check( editableRow );

        this.UpdateCellsEditorVisibility( inspector );
      }

      var dataRow = row as DataRow;
      if( dataRow != null )
      {
        // Set this row's visual common state as MouseOver
        dataRow.SetCommonState( this.ResolveRowCommonState( dataRow.IsSelected, true, dataRow.IsAlternate ), true );
      }
    }

    private void OnMouseLeaveRow( object sender, XceedRoutedEventArgs args )
    {
      var row = args.OriginalSource as Row;
      if( row == null )
        return;

      this.CurrentMouseOverRow = null;

      var editableRow = row as EditableRow;
      if( editableRow != null )
      {
        var inspector = CellEditorVisibilityInspector.Create( this ).Check( editableRow );

        this.UpdateCellsEditorVisibility( inspector );
      }

      var dataRow = row as DataRow;
      if( dataRow != null )
      {
        // Set this row's visual common state as not MouseOver
        dataRow.SetCommonState( this.ResolveRowCommonState( dataRow.IsSelected, false, dataRow.IsAlternate ), true );
      }
    }

    private void OnMouseEnterGroupHeader( object sender, XceedRoutedEventArgs args )
    {
      GroupHeaderControl groupContainer = ( ( GroupHeaderControl )args.OriginalSource );
      // Set this groupContainer's visual state as MouseOver
      this.UpdateGroupHeaderNavigationToolsVisibility( groupContainer, true );
    }

    private void OnMouseLeaveGroupHeader( object sender, XceedRoutedEventArgs args )
    {
      GroupHeaderControl groupContainer = ( ( GroupHeaderControl )args.OriginalSource );
      // Set this groupContainer's visual state as not MouseOver
      this.UpdateGroupHeaderNavigationToolsVisibility( groupContainer, true );
    }

    private void OnGroupSearchBoxFocus( object sender, XceedRoutedEventArgs args )
    {
      // Update the group-navigation searchbox visibility
      GroupHeaderControl groupContainer = ( ( GroupHeaderControl )args.OriginalSource );
      List<DataGridGroupConfiguration> groupConfigurationList = this.GetGroupConfigurationForPath( groupContainer.GroupPath );
      string searchBoxVisibility = this.ResolveGroupNavigationSearchBoxVisibilityState( groupConfigurationList,
                                                                                        groupContainer.IsMouseOverGroupHeader,
                                                                                        groupContainer.SearchBoxHasFocus );
      groupContainer.SetGroupNavigationSearchBoxVisibilityState( searchBoxVisibility, true );
    }

    private void OnToggleExpansionGroup( object sender, XceedRoutedEventArgs args )
    {
      GroupHeaderControl groupContainer = ( ( GroupHeaderControl )args.OriginalSource );

      if( this.GetInheritedAllowGroupCollapsing( groupContainer.GroupPath ) )
      {
        DataGridPath dataGridPath = new DataGridPath( groupContainer.GroupPath );
        if( this.DataGridContext.IsGroupExpanded( dataGridPath ) )
        {
          //collapse
          groupContainer.SetExpansiontState( GroupHeaderControl.ExpansionStateCollapsed, true );
        }
        else
        {
          //expand
          groupContainer.SetExpansiontState( GroupHeaderControl.ExpansionStateExpanded, true );
        }
        this.DataGridContext.ToggleGroupExpansion( dataGridPath );
      }
    }

    private void OnDataSourceExpansionChanged( object sender, ExpansionChangedEventArgs e )
    {
      UpdateRequest request = new UpdateRequest( true );

      if( e.Action == ExpansionAction.Expand )
      {
        request.UpdateDetails.ExpandedPath = e.Path;
      }

      // Update animation of collapse/expand
      this.SetData( request );
    }

    private void OnExpandGroup( object sender, XceedRoutedEventArgs args )
    {
      GroupHeaderControl groupContainer = ( ( GroupHeaderControl )args.OriginalSource );

      if( this.GetInheritedAllowGroupCollapsing( groupContainer.GroupPath ) && !this.DataGridContext.IsGroupExpanded( new DataGridPath( groupContainer.GroupPath ) ) )
      {
        //expand
        this.DataGridContext.ExpandGroup( new DataGridPath( groupContainer.GroupPath ) );
        groupContainer.SetExpansiontState( GroupHeaderControl.ExpansionStateExpanded, true );
      }
    }

    private void OnCollapseGroup( object sender, XceedRoutedEventArgs args )
    {
      GroupHeaderControl groupContainer = ( ( GroupHeaderControl )args.OriginalSource );

      if( this.GetInheritedAllowGroupCollapsing( groupContainer.GroupPath ) && this.DataGridContext.IsGroupExpanded( new DataGridPath( groupContainer.GroupPath ) ) )
      {
        //collapse
        this.DataGridContext.CollapseGroup( new DataGridPath( groupContainer.GroupPath ) );
        groupContainer.SetExpansiontState( GroupHeaderControl.ExpansionStateCollapsed, true );
      }
    }

    private void OnGotoSearchGroup( object sender, XceedRoutedEventArgs args )
    {
      XceedRoutedEventSearchGroupEventArgs e = ( XceedRoutedEventSearchGroupEventArgs )args;
      GroupNavigationSearchBox searchBox = ( GroupNavigationSearchBox )e.OriginalSource;
      string targetValue = e.Value;

      if( string.IsNullOrEmpty( targetValue ) )
        return;

      GroupHeaderControl groupContainer = ( from control in searchBox.GetAncestors()
                                            let groupHeader = control as GroupHeaderControl
                                            where ( groupHeader != null )
                                            select groupHeader ).FirstOrDefault();
      if( groupContainer == null )
        return;

      DataPath groupPath = groupContainer.GroupPath;
      if( groupPath == null )
        return;

      GroupDescription groupDescription = this.DataGridContext.GroupDescriptions[ groupPath.Depth - 1 ];
      Column targetColumn = this.GetGroupedColumn( groupDescription );
      if( targetColumn == null )
        return;

      Type dataType = this.GetColumnDataType( targetColumn );
      if( dataType.IsNullableStruct() )
      {
        dataType = Nullable.GetUnderlyingType( dataType );
      }

      object targetGroup;

      try
      {
        if( dataType.IsEnum )
        {
          // Convert the string to a value of the enum.
          targetGroup = Enum.Parse( dataType, targetValue, true );
        }
        else
        {
          // Convert the string to the target column's type.
          targetGroup = Convert.ChangeType( targetValue, dataType, null );
        }
      }
      catch
      {
        // If Enum.Parse or Convert.ChangeType throw an exception, raise a notification but
        // swallow the exception so program execution continues.
        this.RaiseNotificationReceived(
          new NotificationReceivedEventArgs(
            NotificationSource.Navigation,
            NotificationType.NavigationIncomplete ) );

        return;
      }

      if( typeof( string ) == targetGroup.GetType() )
      {
        targetGroup = ( ( string )targetGroup ).ToLower();
      }

      GroupDataItem searchItem = new GroupDataItem( targetGroup );
      DataPath targetGroupPath;
      if( groupPath.Depth > 1 )
      {
        targetGroupPath = groupPath.ParentPath.CreateChildPath( searchItem );
      }
      else
      {
        targetGroupPath = new DataPath( searchItem );
      }

      m_rowUpdateManager.NavigateToGroup( targetGroupPath, GroupTarget.Current );
    }

    private void OnGotoPreviousGroup( object sender, XceedRoutedEventArgs args )
    {
      this.GotoGroup( ( GroupHeaderControl )args.OriginalSource, GroupTarget.Previous );
    }

    private void OnGotoNextGroup( object sender, XceedRoutedEventArgs args )
    {
      this.GotoGroup( ( GroupHeaderControl )args.OriginalSource, GroupTarget.Next );
    }

    private void GotoGroup( GroupHeaderControl startLocation, GroupTarget action )
    {
      m_rowUpdateManager.NavigateToGroup( startLocation.GroupPath, action );
    }

    private void OnCellStyleChangedFromRow( object sender, XceedRoutedEventArgs args )
    {
      this.RefreshColumns( true );
    }

    private Column GetGroupedColumn( GroupDescription targetGroup )
    {
      if( targetGroup == null )
        return null;

      Column targetColumn = ( from column in this.Columns
                              where ( column.GroupDescription == targetGroup )
                              select column ).FirstOrDefault();
      if( targetColumn != null )
        return targetColumn;

      PropertyGroupDescription propertyGroupDescription = targetGroup as PropertyGroupDescription;
      if( propertyGroupDescription == null )
        return null;

      string propertyName = propertyGroupDescription.PropertyName;

      return ( from column in this.Columns
               where ( column.SortFieldName == propertyName )
               select column ).FirstOrDefault();
    }

    private Style GetInheritedCellStyle( DataCell cell, Column parentColumn, Row parentRow )
    {
      if( ( parentColumn != null ) && ( parentColumn.CellStyle != null ) )
        return parentColumn.CellStyle;

      if( ( parentRow != null ) && ( parentRow.CellStyle != null ) )
        return parentRow.CellStyle;

      if( this.CellStyle != null )
        return this.CellStyle;

      return null;
    }

    private Style GetInheritedCellStyle( ColumnManagerCell cell, Column parentColumn, Row parentRow )
    {
      if( ( parentColumn != null ) && ( parentColumn.ColumnManagerCellStyle != null ) )
        return parentColumn.ColumnManagerCellStyle;

      if( ( parentRow != null ) && ( parentRow.CellStyle != null ) )
        return parentRow.CellStyle;

      if( this.ColumnManagerCellStyle != null )
        return this.ColumnManagerCellStyle;

      return null;
    }











    private Style GetInheritedCellStyle( Cell cell, Column parentColumn, Row parentRow )
    {
      if( ( parentRow != null ) && ( parentRow.CellStyle != null ) )
        return parentRow.CellStyle;

      return null;
    }

    private Style GetInheritedCellViewerStyle( Cell cell, Column parentColumn, Row parentRow )
    {
      if( ( parentColumn != null ) && ( parentColumn.CellContentStyle != null ) )
        return parentColumn.CellContentStyle;

      return null;
    }

    private Style GetInheritedCellEditorStyle( Cell cell, Column parentColumn, Row parentRow )
    {
      if( ( parentColumn != null ) && ( parentColumn.CellEditorStyle != null ) )
        return parentColumn.CellEditorStyle;

      return null;
    }

    private bool GetInheritedReadOnly( Column column )
    {
      if( column == null )
        throw new ArgumentNullException( "column" );

      return column.ReadOnly.GetValueOrDefault( this.ReadOnly );
    }

    private TextTrimming GetInheritedTextTrimming( Column column )
    {
      if( column == null )
        return TextTrimming.None;

      return column.TextTrimming;
    }

    private void OnAllowColumnResizeChangedFromColumnManagerRow( object sender, XceedRoutedEventArgs args )
    {
      ColumnManagerRow row = ( ColumnManagerRow )args.OriginalSource;

      // Update hit test visibility for the ColumnManagerCells in the ColumnManagerRow
      foreach( ColumnElementWrapper element in row.RenderedElements )
      {
        ColumnManagerCell cell = ( ColumnManagerCell )element.ColumnElement;
        this.UpdateColumnResizingThumbHitTestVisibility( cell );
      }
    }

    private void UpdateColumnResizingThumbHitTestVisibility( ColumnManagerCell cell )
    {
      bool allowResize = false;

      Column parentColumn = cell.ParentColumn;
      if( ( parentColumn != null ) && ( parentColumn.AllowResize.HasValue ) )
      {
        allowResize = parentColumn.AllowResize.Value;
      }
      else
      {
        ColumnManagerRow parentRow = cell.ParentRow as ColumnManagerRow;
        if( parentRow != null && ( parentRow.AllowColumnResize.HasValue ) )
        {
          allowResize = parentRow.AllowColumnResize.Value;
        }
        else
        {
          allowResize = this.AllowColumnResize;
        }
      }

      // Update the HitTestVisibility of the ColumnResizingThumb according to 
      // the ColumnManagerRow.AllowColumnResize if ColumnManagerRow is not null.
      // Default is true.
      cell.SetHitTestVisible( allowResize );
    }

    private void UpdateFixedColumnToggleButtonState( ColumnManagerCell cell, Column column )
    {
      Column parentColumn = cell.ParentColumn;
      if( ( parentColumn != null ) && this.IsColumnFixed( parentColumn ) )
      {
        cell.SetFixedColumnToggleButtonState( ColumnManagerCell.FixedColumnToggleButtonStateFixed, true );
        return;
      }
      cell.SetFixedColumnToggleButtonState( ColumnManagerCell.FixedColumnToggleButtonStateScrolling, true );
    }

    private void RefreshFixedColumnToggleButtonVisibility()
    {
      // Update the fixed "pin" on each ColumnManagerCell in the ColumnManagerRow depending on the values of the ParentColumn
      Action<ColumnManagerRow> updateColumnManagerCell = ( columnManagerRow ) =>
      {
        foreach( ColumnElementWrapper element in columnManagerRow.RenderedElements )
        {
          ColumnManagerCell cell = ( ColumnManagerCell )element.ColumnElement;
          this.RefreshFixedColumnToggleButtonVisibility( cell, cell.ParentColumn, true );
        }
      };

      ColumnManagerRowVisitor visitor = new ColumnManagerRowVisitor( updateColumnManagerCell );
      this.DataGridPanel.Accept( visitor );
    }

    private void RefreshFixedColumnToggleButtonVisibility( ColumnManagerCell cell, Column parentColumn, bool useTransitions )
    {
      if( ( this.FixedColumnToggleButtonVisibility == FixedColumnToggleButtonVisibility.Auto )
       && ( parentColumn != null )
       && ( cell.IsMouseOver
            && this.AllowFixedColumns
            && this.CanShowFixedColumnToggleButton( parentColumn ) ) )
      {
        cell.SetFixedColumnToggleButtonVisibleState( ColumnManagerCell.FixedColumnToggleButtonVisible, useTransitions );
      }
      else if( ( this.FixedColumnToggleButtonVisibility == FixedColumnToggleButtonVisibility.Always )
             && this.AllowFixedColumns
             && ( parentColumn != null )
             && ( this.CanShowFixedColumnToggleButton( parentColumn ) ) )
      {
        cell.SetFixedColumnToggleButtonVisibleState( ColumnManagerCell.FixedColumnToggleButtonVisible, useTransitions );
      }
      else
      {
        cell.SetFixedColumnToggleButtonVisibleState( ColumnManagerCell.FixedColumnToggleButtonHidden, useTransitions );
      }
    }

    private bool CanShowFixedColumnToggleButton( Column column )
    {
      IEnumerable<Column> orderedColumns = this.GetOrderedColumns();

      List<Column> scrollableColumns = this.GetScrollableColumns( orderedColumns ).ToList();

      if( scrollableColumns.Count > 0 )
      {
        if( object.ReferenceEquals( scrollableColumns.First(), column ) || object.ReferenceEquals( scrollableColumns.Last(), column ) )
          return true;
      }


      List<Column> leftFixedColumns = this.GetFixedColumns( orderedColumns, true ).ToList();
      List<Column> rightFixedColumns = this.GetFixedColumns( orderedColumns, false ).ToList();
      if( ( leftFixedColumns.Count > 0 ) && object.ReferenceEquals( leftFixedColumns.Last(), column ) )
        return true;
      if( ( rightFixedColumns.Count > 0 ) && object.ReferenceEquals( rightFixedColumns.Last(), column ) )
        return true;

      return false;
    }





    private void OnDefaultColumnTitleTemplateChangedFromColumnManagerRow( object sender, XceedRoutedEventArgs args )
    {
      ColumnManagerRow row = ( ColumnManagerRow )args.OriginalSource;

      // Update the cell content template on each ColumnManagerCell dependanding on values from ParentColumn and ParentRow
      this.RefreshColumns( true );
    }

    private void UpdateGroupByItemsTitle()
    {

    }









    private DataTemplate GetInheritedCellContentTemplate( ColumnManagerCell cell )
    {
      var column = cell.ParentColumn;
      if( column != null )
      {
        var template = column.TitleTemplate;
        if( template != null )
          return template;
      }

      var parentRow = cell.ParentRow as ColumnManagerRow;
      if( parentRow != null )
      {
        var template = parentRow.DefaultColumnTitleTemplate;
        if( template != null )
          return template;
      }

      return null;
    }

    private DataTemplate GetInheritedCellContentTemplate( Cell targetCell )
    {
      var column = targetCell.ParentColumn;
      if( column == null )
        return null;

      return column.CellContentTemplate;
    }

    private DataTemplate GetInheritedCellEditorTemplate( Cell targetCell )
    {
      var column = targetCell.ParentColumn;
      if( column == null )
        return null;

      return column.CellEditorTemplate;
    }

    private void UpdateAllGroupByItemRemoveButtonVisibility()
    {

    }

    private void OnMouseEnterCell( object sender, XceedRoutedEventArgs args )
    {
      var cell = args.OriginalSource as Cell;
      if( cell == null )
        return;

      this.CurrentMouseOverColumn = cell.ParentColumn;

      // Set this cell's visual common state as MouseOver
      this.UpdateColumnElementCommonState( cell, cell.ParentColumnContainer.IsDragged, true, false, true );

      var editableCell = cell as EditableCell;
      if( editableCell != null )
      {
        var inspector = CellEditorVisibilityInspector.Create( this ).Check( editableCell );

        this.UpdateCellsEditorVisibility( inspector );
      }

      var columnManagerCell = cell as ColumnManagerCell;
      if( columnManagerCell != null )
      {
        this.RefreshFixedColumnToggleButtonVisibility( columnManagerCell, columnManagerCell.ParentColumn, true );
      }
    }

    private void OnMouseLeaveCell( object sender, XceedRoutedEventArgs args )
    {
      var cell = args.OriginalSource as Cell;
      if( cell == null )
        return;

      this.CurrentMouseOverColumn = null;

      // Set this cell's visual common state as not MouseOver
      this.UpdateColumnElementCommonState( cell, cell.ParentColumnContainer.IsDragged, false, false, true );

      var editableCell = cell as EditableCell;
      if( editableCell != null )
      {
        var inspector = CellEditorVisibilityInspector.Create( this ).Check( editableCell );

        this.UpdateCellsEditorVisibility( inspector );
      }

      var columnManagerCell = cell as ColumnManagerCell;
      if( columnManagerCell != null )
      {
        this.RefreshFixedColumnToggleButtonVisibility( columnManagerCell, columnManagerCell.ParentColumn, true );
      }
    }

    private void OnColumnManagerCellIsPressedChanged( object sender, XceedRoutedEventArgs args )
    {
      ColumnManagerCell cell = ( ( ColumnManagerCell )args.OriginalSource );
      this.UpdateColumnElementCommonState( cell, cell.ParentColumnContainer.IsDragged, cell.IsMouseOver, cell.IsPressed, true );
    }

    private void UpdateColumnsVisiblePosition()
    {
      // Do not change VisiblePosition of any columns
      // while the DataGridControl is initializing
      // to avoid overwriting the value that could have 
      // been affected on the Column explicitly.
      if( this.IsInitializing )
        return;

      ColumnCollection columnCollection = this.DataGridContext.Columns;

      IEnumerable<Column> sortedColumns =
           from col in columnCollection
           orderby col.VisiblePosition //"ascending" is default
           select col;

      List<Column> sortedColumnsList = sortedColumns.ToList();
      for( int i = 0; i < sortedColumnsList.Count; i++ )
      {
        columnCollection[ sortedColumnsList[ i ].FieldName ].VisiblePosition = i;  //reset VisiblePosition from 0 to collectionCount
      }
    }

    private void OnVerticalScroll( object sender, ScrollEventArgs e )
    {
      this.OnScroll( e, ref m_lastVerticalValue, this.SetData, true );
    }

    private void OnHorizontalScroll( object sender, ScrollEventArgs e )
    {
      this.OnScroll( e, ref m_lastHorizontalValue, this.SetColumns );
    }

    private void OnScroll( ScrollEventArgs e,
                           ref double lastValue,
                           Action<UpdateRequest> dataSetter,
                           bool useItemScrollingBehaviour = false )
    {
      if( e.ScrollEventType == ScrollEventType.ThumbPosition )
        return;

      if( useItemScrollingBehaviour )
      {
        if( e.ScrollEventType == ScrollEventType.EndScroll )
        {
          //When using immediate scrolling, the ThumbTrack event will handle the index change
          if( this.ItemScrollingBehavior == DataGrid.ItemScrollingBehavior.Immediate )
            return;
        }
        else if( e.ScrollEventType == ScrollEventType.ThumbTrack )
        {
          //When using deferred scrolling, the EndScroll event will handle the index change
          if( this.ItemScrollingBehavior == ItemScrollingBehavior.Deferred )
            return;
        }
      }
      else if( e.ScrollEventType == ScrollEventType.EndScroll )
      {
        return;
      }

      UpdateRequest updateInfo = null;
      if( ( e.ScrollEventType == ScrollEventType.ThumbTrack )
       || ( e.ScrollEventType == ScrollEventType.EndScroll ) )
      {
        double oldIndex = lastValue;
        double newIndex = e.NewValue;
        double diff = newIndex - oldIndex;
        if( diff != 0 )
        {
          updateInfo = new ScrollUpdateRequest( false, diff );
        }
      }
      else
      {
        updateInfo = new ScrollUpdateRequest( true, e.ScrollEventType );
      }

      lastValue = e.NewValue;

      if( updateInfo != null )
      {
        dataSetter( updateInfo );
      }
    }

    private void OnRowsBackgroundChange( Brush rowBackground )
    {
      DataRowVisitor visitor = new DataRowVisitor( ChildrenPolicy.RenderedChildrenOnly,
        ( row ) => row.SetBackground( rowBackground ) );
      this.RootContainer.Accept( visitor );
    }

    private void OnRowsAlternatingBackgroundChange( Brush rowAlternatingBackground )
    {
      DataRowVisitor visitor = new DataRowVisitor( ChildrenPolicy.RenderedChildrenOnly,
        ( row ) => row.SetAlternatingBackground( rowAlternatingBackground ) );
      this.RootContainer.Accept( visitor );
    }

    private void UpdateRowCommonState( DataRow row )
    {
      // Set this row's visual common state as selected/not selected
      row.SetCommonState( this.ResolveRowCommonState( row.IsSelected, false, row.IsAlternate ), true );
    }

    private void UpdateAllGroupContainerNavigationToolsVisibility()
    {
      Action<VirtualGroupContainer> groupAction = ( c ) =>
      {
        Action<HeaderFooterWrapper> headerAction = ( e ) =>
        {
          GroupHeaderControl groupHeader = e.Child as GroupHeaderControl;
          if( groupHeader != null )
          {
            this.UpdateGroupHeaderNavigationToolsVisibility( groupHeader, true );
          }
        };

        c.ApplyToHeadersFooters( headerAction );
      };

      VirtualGroupVisitor visitor = new VirtualGroupVisitor( groupAction );
      this.RootContainer.Accept( visitor );
    }

    private void UpdateGroupHeaderNavigationToolsVisibility( GroupHeaderControl groupContainer, bool useTransitions )
    {
      List<DataGridGroupConfiguration> groupConfigurationList = this.GetGroupConfigurationForPath( groupContainer.GroupPath );
      this.UpdateGroupHeaderNavigationToolsVisibility( groupContainer, groupConfigurationList, useTransitions );
    }

    private void UpdateGroupHeaderNavigationToolsVisibility( GroupHeaderControl groupContainer, List<DataGridGroupConfiguration> groupConfigurationList, bool useTransitions )
    {
      string searchBoxVisibility = this.ResolveGroupNavigationSearchBoxVisibilityState( groupConfigurationList,
                                                                                        groupContainer.IsMouseOverGroupHeader,
                                                                                        groupContainer.SearchBoxHasFocus );
      string buttonVisibility = this.ResolveGroupNavigationButtonsVisibilityState( groupConfigurationList, groupContainer.IsMouseOverGroupHeader );
      string expensionVisibility = this.ResolveGroupExpansionButtonsVisibilityState( groupConfigurationList );

      groupContainer.SetGroupNavigationSearchBoxVisibilityState( searchBoxVisibility, useTransitions );
      groupContainer.SetGroupNavigationButtonsVisibilityState( buttonVisibility, useTransitions );
      groupContainer.SetGroupExpansionButtonsVisibilityState( expensionVisibility, useTransitions );
    }

    private string ResolveGroupNavigationSearchBoxVisibilityState( List<DataGridGroupConfiguration> groupConfigurationList, bool isMouseOver, bool searchBoxHasFocus )
    {
      bool allowGroupNavigation = this.GetInheritedAllowGroupNavigation( groupConfigurationList );
      GroupNavigationModes groupNavigationMode = this.GetInheritedGroupNavigationModes( groupConfigurationList );

      if( allowGroupNavigation
       && ( isMouseOver || searchBoxHasFocus )
       && ( ( groupNavigationMode & GroupNavigationModes.SearchBox ) == GroupNavigationModes.SearchBox ) )
      {
        return GroupHeaderControl.SearchBoxVisibilityStateVisible;
      }
      else
      {
        return GroupHeaderControl.SearchBoxVisibilityStateHidden;
      }
    }

    private string ResolveGroupNavigationButtonsVisibilityState( List<DataGridGroupConfiguration> groupConfigurationList, bool isMouseOver )
    {
      bool allowGroupNavigation = this.GetInheritedAllowGroupNavigation( groupConfigurationList );
      GroupNavigationModes groupNavigationMode = this.GetInheritedGroupNavigationModes( groupConfigurationList );

      if( allowGroupNavigation
      && isMouseOver
      && ( ( groupNavigationMode & GroupNavigationModes.NavigationButtons ) == GroupNavigationModes.NavigationButtons ) )
      {
        return GroupHeaderControl.NavigationButtonVisibilityStateVisible;
      }
      else
      {
        return GroupHeaderControl.NavigationButtonVisibilityStateHidden;
      }
    }

    private string ResolveGroupExpansionButtonsVisibilityState( List<DataGridGroupConfiguration> groupConfigurationList )
    {
      bool allowGroupCollapsing = this.GetInheritedAllowGroupCollapsing( groupConfigurationList );

      if( allowGroupCollapsing )
      {
        return GroupHeaderControl.ExpansionButtonVisibilityStateVisible;
      }
      else
      {
        return GroupHeaderControl.ExpansionButtonVisibilityStateHidden;
      }
    }

    internal List<DataGridGroupConfiguration> GetGroupConfigurationForPath( DataPath groupPath )
    {

      if( groupPath == null )
        throw new ArgumentNullException( "groupPath" );

      object groupData = groupPath.LastChild.Data;

      return this.GetGroupConfigurationForDepth( groupPath.Depth, groupData );
    }

    internal List<DataGridGroupConfiguration> GetGroupConfigurationForDepth( int groupDepth, object groupData )
    {

      if( groupDepth > this.DataGridContext.GroupDescriptions.Count )
        return null;//throw new DataInternalException("Can't access an out of bound value");

      List<DataGridGroupConfiguration> groupConfigurationsList = new List<DataGridGroupConfiguration>();
      DataGridGroupDescription groupDescription = this.DataGridContext.GroupDescriptions[ groupDepth - 1 ] as DataGridGroupDescription;

      // Respect the priority order for groupConfigurations
      if( ( groupDescription != null ) && ( groupDescription.GroupConfiguration != null ) )
      {
        groupConfigurationsList.Add( groupDescription.GroupConfiguration );
      }

      if( this.GroupConfigurationSelector != null )
      {
        DataGridGroupConfiguration selectedConfig = this.GroupConfigurationSelector.Select( groupDepth - 1, groupData );
        if( selectedConfig != null )
        {
          groupConfigurationsList.Add( selectedConfig );
        }
      }

      if( this.DefaultGroupConfiguration != null )
      {
        groupConfigurationsList.Add( this.DefaultGroupConfiguration );
      }

      groupConfigurationsList.Add( DataGridGroupConfiguration.DefaultGroupConfiguration );

      return groupConfigurationsList;
    }

    private double GetColumnElementsIdentForDepth( int parentDepth )
    {
      if(parentDepth < 0)
        throw new DataGridInternalException();

      double offset = 0d;
      List<DataGridGroupConfiguration> configs;
      int groupLevelCount = this.DataGridContext.GroupDescriptions.Count;

      if( parentDepth == 0 )
      {
        offset = RootHost.RootHostInitialOffset;
        parentDepth = 1;
      }

      while( parentDepth <= groupLevelCount )
      {
        configs = this.GetGroupConfigurationForDepth( parentDepth, null );
        offset += this.GetInheritedSublevelIndent( configs );
        parentDepth++;
      }

      return offset;
    }

    private bool GetInheritedAllowGroupCollapsing( DataPath groupPath )
    {
      List<DataGridGroupConfiguration> groupConfigurationList = this.GetGroupConfigurationForPath( groupPath );
      return this.GetInheritedAllowGroupCollapsing( groupConfigurationList );
    }

    private bool GetInheritedAllowGroupNavigation( List<DataGridGroupConfiguration> groupConfigurationList )
    {
      if( groupConfigurationList.Count == 0 )
        return this.AllowGroupNavigation;

      return this.GetGroupConfigurationAllowGroupNavigation( groupConfigurationList ).GetValueOrDefault( this.AllowGroupNavigation );
    }

    private GroupNavigationModes GetInheritedGroupNavigationModes( List<DataGridGroupConfiguration> groupConfigurationList )
    {
      if( groupConfigurationList.Count == 0 )
        return this.GroupNavigationModes;

      return this.GetGroupConfigurationGroupNavigationModes( groupConfigurationList ).GetValueOrDefault( this.GroupNavigationModes );
    }

    private bool GetInheritedAllowGroupCollapsing( List<DataGridGroupConfiguration> groupConfigurationList )
    {
      if( groupConfigurationList.Count == 0 )
        return this.AllowGroupCollapsing;

      return this.GetGroupConfigurationAllowGroupCollapsing( groupConfigurationList ).GetValueOrDefault( this.AllowGroupCollapsing );
    }

    private double GetInheritedSublevelIndent( List<DataGridGroupConfiguration> groupConfigurationList )
    {
      if( groupConfigurationList.Count == 0 )
      {
        Debug.Assert( false );
        return DataGridControl.DefaultGroupSublevelIndent;
      }

      return this.GetGroupConfigurationSublevelIndent( groupConfigurationList ).GetValueOrDefault( DataGridControl.DefaultGroupSublevelIndent );
    }

    private DataTemplate GetGroupConfigurationGroupValueTemplate( List<DataGridGroupConfiguration> groupConfigurationsList )
    {
      DataGridGroupConfiguration groupConfiguration = groupConfigurationsList.FirstOrDefault( ( groupConfig ) => groupConfig.GroupValueTemplate != null );
      return ( groupConfiguration != null ) ? groupConfiguration.GroupValueTemplate : null;
    }

    private Style GetGroupConfigurationGroupHeaderStyle( List<DataGridGroupConfiguration> groupConfigurationsList )
    {
      DataGridGroupConfiguration groupConfiguration = groupConfigurationsList.FirstOrDefault( ( groupConfig ) => groupConfig.GroupHeaderStyle != null );
      return ( groupConfiguration != null ) ? groupConfiguration.GroupHeaderStyle : null;
    }

    private bool? GetGroupConfigurationAllowGroupNavigation( List<DataGridGroupConfiguration> groupConfigurationsList )
    {
      DataGridGroupConfiguration groupConfiguration = groupConfigurationsList.FirstOrDefault( ( groupConfig ) => groupConfig.AllowGroupNavigation != null );
      return ( groupConfiguration != null ) ? groupConfiguration.AllowGroupNavigation : null;
    }

    private GroupNavigationModes? GetGroupConfigurationGroupNavigationModes( List<DataGridGroupConfiguration> groupConfigurationsList )
    {
      DataGridGroupConfiguration groupConfiguration = groupConfigurationsList.FirstOrDefault( ( groupConfig ) => groupConfig.GroupNavigationModes != null );
      return ( groupConfiguration != null ) ? groupConfiguration.GroupNavigationModes : null;
    }

    private bool? GetGroupConfigurationAllowGroupCollapsing( List<DataGridGroupConfiguration> groupConfigurationsList )
    {
      DataGridGroupConfiguration groupConfiguration = groupConfigurationsList.FirstOrDefault( ( groupConfig ) => groupConfig.AllowGroupCollapsing != null );
      return ( groupConfiguration != null ) ? groupConfiguration.AllowGroupCollapsing : null;
    }

    private double? GetGroupConfigurationSublevelIndent( List<DataGridGroupConfiguration> groupConfigurationsList )
    {
      DataGridGroupConfiguration groupConfiguration = groupConfigurationsList.FirstOrDefault( ( groupConfig ) => groupConfig.SublevelIndent != null );
      return ( groupConfiguration != null ) ? groupConfiguration.SublevelIndent : ( double? )null;
    }

    private void UpdateColumnElementCommonState( Cell element, bool isDragged, bool isMouseOver, bool isPressed, bool useTransitions )
    {
      if( isDragged )
        element.SetCommonState( Cell.CommonStateDragged, useTransitions );
      else if( isPressed )
        element.SetCommonState( Cell.CommonStatePressed, useTransitions );
      else if( isMouseOver )
        element.SetCommonState( Cell.CommonStateMouseOver, useTransitions );
      else
        element.SetCommonState( Cell.CommonStateNormal, useTransitions );
    }

    private void InvalidateColumnManagerRowAllowColumnResize()
    {
      Action<ColumnManagerRow> updateCell = ( columnManagerRow ) =>
      {
        foreach( ColumnElementWrapper element in columnManagerRow.RenderedElements )
        {
          ColumnManagerCell cell = ( ColumnManagerCell )element.ColumnElement;
          this.UpdateColumnResizingThumbHitTestVisibility( cell );
        }
      };

      ColumnManagerRowVisitor visitor = new ColumnManagerRowVisitor( updateCell );
      this.DataGridPanel.Accept( visitor );
    }

    private void RefreshDefaultHeadersFooters()
    {
      if( this.UseDefaultHeadersFooters )
      {
        this.RefreshDefaultHeaderFooter( typeof( ColumnManagerRow ), this.FixedHeaders );


        // Add the missing footers.
        this.RefreshDefaultHeaderFooter( typeof( NotificationControl ), this.FixedFooters );
      }
      else
      {
        // Remove the headers and footers which have the DefaultHeaderFooterType attached to them.
        this.CleanUpDefaultHeaderFooter( this.FixedHeaders );
        this.CleanUpDefaultHeaderFooter( this.FixedFooters );
      }
    }

    private void RefreshDefaultHeaderFooter( Type newHeaderFooterType, Collection<UIElement> list )
    {
      // Find the first header/footer in the list, of a specific type, which is a default header/footer
      UIElement currentHeaderFooter = list.FirstOrDefault( ( x ) => ( object.Equals( x.GetType(), newHeaderFooterType )
                                                                      && DataGridControl.GetIsDefaultHeaderFooter( x ) ) );

      HeaderFooterTypes itemType = this.GetHeaderFooterType( newHeaderFooterType );
      // this is the wanted default header, refresh it
      if( ( this.DefaultHeadersFooters & itemType ) == itemType )
      {
        // item was not in header/footer list, add it
        if( currentHeaderFooter == null )
        {
          currentHeaderFooter = this.CreateHeaderFooter( list, itemType );
        }
        DataGridControl.SetIsDefaultHeaderFooter( currentHeaderFooter, true );
      }
      else
      {
        // We must remove the header/footer, if present.
        if( currentHeaderFooter != null )
        {
          currentHeaderFooter.ClearValue( DataGridControl.IsDefaultHeaderFooterProperty );
          list.Remove( currentHeaderFooter );
        }
      }
    }

    private void CleanUpDefaultHeaderFooter( IList<UIElement> list )
    {
      var count = list.Count;
      for( var i = count - 1; i >= 0; i-- )
      {
        if( !DataGridControl.GetIsDefaultHeaderFooter( list[ i ] ) )
          continue;

        list.RemoveAt( i );
      }
    }

    private HeaderFooterTypes GetHeaderFooterType( Type newType )
    {
      if( newType == null )
        return HeaderFooterTypes.None;

      if( object.Equals( newType, typeof( ColumnManagerRow ) ) )
        return HeaderFooterTypes.ColumnManagerRow;
      if( object.Equals( newType, typeof( NotificationControl ) ) )
        return HeaderFooterTypes.NotificationControl;

      return HeaderFooterTypes.None;
    }

    private UIElement CreateHeaderFooter( Collection<UIElement> list, HeaderFooterTypes headerFooterType )
    {
      UIElement element = null;

      switch( headerFooterType )
      {
        case HeaderFooterTypes.ColumnManagerRow:
          element = this.CreateColumnManagerRow( list );
          break;

        case HeaderFooterTypes.FilterRow:
          element = this.CreateFilterRow( list );
          break;

        case HeaderFooterTypes.GroupByControl:
          element = this.CreateGroupByControl( list );
          break;

        case HeaderFooterTypes.InsertionRow:
          element = this.CreateInsertionRow( list );
          break;

        case HeaderFooterTypes.NotificationControl:
          element = this.CreateNotificationControl( list );
          break;
      }

      return element;
    }

    private UIElement CreateColumnManagerRow( Collection<UIElement> list )
    {
      ColumnManagerRow columnManagerRow = new ColumnManagerRow();
      list.Insert( Math.Min( DefaultHeaderColumnManagerRowPosition, list.Count ), columnManagerRow );
      return columnManagerRow;
    }

    private UIElement CreateFilterRow( Collection<UIElement> list )
    {
      return null;
    }

    private UIElement CreateGroupByControl( Collection<UIElement> list )
    {
      return null;
    }

    private UIElement CreateInsertionRow( Collection<UIElement> list )
    {
      return null;
    }

    private UIElement CreateNotificationControl( Collection<UIElement> list )
    {
      NotificationControl notificationControl = new NotificationControl();
      list.Insert( Math.Min( DefaultFooterNotificationControlPosition, list.Count ), notificationControl );
      return notificationControl;
    }

    private bool GetInheritedAllowSort( ColumnManagerCell cell )
    {
      if( cell == null )
        throw new ArgumentNullException( "cell" );

      // We first return the value defined on the column, if any.
      Nullable<bool> parentColumnAllowSort = cell.ParentColumn.AllowSort;
      if( parentColumnAllowSort.HasValue )
      {
        return parentColumnAllowSort.Value;
      }

      // Return the value defined on the ColumnManagerRow, if present.
      ColumnManagerRow parentRow = cell.ParentRow as ColumnManagerRow;
      if( ( parentRow != null ) && ( parentRow.AllowColumnSort.HasValue ) )
      {
        return parentRow.AllowColumnSort.Value;
      }

      return this.AllowSort;
    }












    private void ResetDataSourceEnumerator()
    {
      if( m_enumerator != null )
      {
        m_enumerator.DataChanged -= this.OnDataEnumeratorDataChanged;
      }
      m_enumerator = null;
    }

    private void UpdateEnumerator()
    {
      this.ResetDataSourceEnumerator();

      m_enumerator = this.DataGridContext.DataSource.GetEnumerator();
      if( m_enumerator != null )
      {
        m_enumerator.DataChanged += this.OnDataEnumeratorDataChanged;
      }
      this.ResetStatContext();

      // Since we are changing the m_dataEnumerator, we must invalidate the
      // ScrollToTop and ScrollToBottom command since they depends on
      // that varaible.
      if( this.ScrollToTopCommand != null )
      {
        ( ( DataGridCommand )this.ScrollToTopCommand ).RaiseCanExecuteChanged();
        ( ( DataGridCommand )this.ScrollToBottomCommand ).RaiseCanExecuteChanged();
      }
    }

    private void OnDataEnumeratorDataChanged( object sender, DataChangedEventArgs e )
    {
      if( e.Action == DataChangedAction.Reset )
      {
        this.CurrentDataPath = null;
        this.ClearSelectionAnchor();
        this.SelectedItem = null;
      }
      else if( e.Action == DataChangedAction.Remove )
      {
        DataPath oldDataPath = e.OldItem as DataPath;
        if( oldDataPath != null )
        {
          if( object.Equals( this.CurrentDataPath, oldDataPath ) )
          {
            this.CurrentDataPath = null;
          }
          if( object.Equals( m_anchorPath, oldDataPath ) )
          {
            this.ClearSelectionAnchor();
          }
          if( object.Equals( this.SelectedItem, oldDataPath.LastChild.Data ) )
          {
            this.SetSelectedItemInternal( null );
          }
        }
      }

      if( ( e.Action == DataChangedAction.Add ) || ( e.Action == DataChangedAction.Remove )
        || ( e.Action == DataChangedAction.Reset ) || ( e.Action == DataChangedAction.Replace )
        || ( e.Action == DataChangedAction.ItemChanged ) )
      {
        //Any modification may make the StatContext invalid.
        this.ResetStatContext();

        this.RefreshData( false );
      }
    }

    private void ResetStatContext()
    {
      if( ( this.DataGridContext.DataSource == null )
        || ( this.DataGridContext.DataSource.Provider == null )
        || ( this.DataGridContext.DataSource.Provider.GetType() == typeof( EmptyDataSourceProvider ) ) )
      {
        return;
      }

      if( m_enumerator != null )
      {
        StatParameters statParameters = new StatParameters( this.StatFunctions );
        StatResults statResults = m_enumerator.SyncGetStatValues( statParameters );

        StatContext newStatContext = new StatContext( statParameters.StatFunctions.Select( ( func ) => func.ResultPropertyName ), statResults.Results );

        this.ModifyStatContextForElement( this, newStatContext );

        foreach( UIElement header in this.FixedHeaders )
        {
          this.ModifyStatContextForElement( header, newStatContext );
        }

        foreach( UIElement footer in this.FixedFooters )
        {
          this.ModifyStatContextForElement( footer, newStatContext );
        }
      }
    }

    private void OnDataSourceChanged( object sender, Xceed.Silverlight.Data.SourceChangedEventArgs e )
    {
      this.InvalidateData();
    }

    private void InvalidateData()
    {
      this.RemoveAllContainers();
      this.UpdateRowsCellOffset();
      this.UpdateRootHostOffset();  
      this.UpdateColumnsSortDirection();
      this.DataGridContext.UpdateSourceFilterExpression();

      this.CancelEdit();

      if( this.DataGridContext.DataSource.IsPrimaryKeyVolatile )
      {
        this.UnselectAll();
        this.SetSelectedItemInternal( null );
        this.CurrentPath = null;
      }

      this.UpdateEnumerator();

      //Update the UI starting by displaying the CurrentItem.
      DataPath currentPath = null;
      if( this.DataGridContext.CurrentItem != null )
      {
        currentPath = this.DataSource.DataHelper.Convert( this.DataGridContext.CurrentItem );
        this.DataGridContext.CurrentPath = new DataGridPath( currentPath );
      }
      else if( this.DataGridContext.CurrentPath != null )
      {
        this.DataGridContext.CurrentPath = null;
      }

      UpdateRequest updateInfo = new ReferenceUpdateRequest( false, currentPath, FetchDirection.Forward );
      updateInfo.UpdateDetails.RowPreload = ( currentPath == null );

      this.ClearSelectionAnchor();

      this.SetData( updateInfo );
    }

    // Will set all Column's Direction and ColumnManagercell's VisualState
    private void UpdateColumnsSortDirection()
    {
      SortDescriptionCollection sortDescriptions = this.DataGridContext.SortDescriptions;
      IDictionary<string, SortDescription> sortLookup = sortDescriptions.ToDictionary( ( s ) => s.PropertyName );

      //Update every column's sorting direction
      foreach( Column column in this.DataGridContext.Columns )
      {
        string fieldName = column.SortFieldName;
        SortDirection direction = SortDirection.None;
        SortDescription description;
        if( sortLookup.TryGetValue( fieldName, out description ) )
        {
          direction = ( description.Direction == ListSortDirection.Ascending )
            ? SortDirection.Ascending
            : SortDirection.Descending;
        }

        column.SortDirection = direction;
      }
    }

    private void SortChangeRequestChanged( ColumnManagerCell cell, SortDirection? sortDirection )
    {
      Column parentColumn = cell.ParentColumn;

      if( ( parentColumn == null ) || !this.GetInheritedAllowSort( cell ) || ( parentColumn.SortFieldName == null ) )
        return;

      SortDirection valueIfToggle = this.ToggleSortDirection( parentColumn.SortDirection );
      SortDirection newSortDirection = sortDirection.GetValueOrDefault( valueIfToggle );

      bool multipleSort = ( ( Keyboard.Modifiers & ModifierKeys.Shift ) == ModifierKeys.Shift );
      this.SetDataSourceSorting( parentColumn.SortFieldName, newSortDirection, multipleSort, true );
    }

    private void SetDataSourceSorting( string fieldName, SortDirection sortDirection, bool multipleSort, bool enableNotifications )
    {
      SortDescriptionCollection sorting = this.DataGridContext.SortDescriptions;

      if( !enableNotifications )
      {
        this.DataGridContext.DataSource.SourceChanged -= this.OnDataSourceChanged;
      }

      if( !multipleSort )
      {
        if( sortDirection == SortDirection.None || !enableNotifications )
        {
          sorting.Clear();
        }
        else
        {
          Debug.Assert( enableNotifications );
          this.DataGridContext.DataSource.SourceChanged -= this.OnDataSourceChanged;
          sorting.Clear();
          this.DataGridContext.DataSource.SourceChanged += this.OnDataSourceChanged;
        }
      }

      if( fieldName != null )
      {

        int fieldIndex = sorting
          .Select( ( s ) => s.PropertyName )
          .ToList().IndexOf( fieldName );



        if( sortDirection == SortDirection.None )
        {
          if( fieldIndex != -1 )
          {
            sorting.RemoveAt( fieldIndex );
          }
        }
        else
        {
          ListSortDirection listDirection = ( sortDirection == SortDirection.Ascending )
            ? ListSortDirection.Ascending
            : ListSortDirection.Descending;

          SortDescription sortDescription = new SortDescription( fieldName, listDirection );

          if( fieldIndex != -1 )
          {
            if( !object.Equals( sorting[ fieldIndex ], sortDescription ) )
            {
              sorting[ fieldIndex ] = sortDescription;
            }
          }
          else
          {
            sorting.Add( sortDescription );
          }
        }
      }

      if( !enableNotifications )
      {
        this.DataGridContext.DataSource.SourceChanged += this.OnDataSourceChanged;
      }
    }

    private SortDirection ToggleSortDirection( SortDirection currentSortDirection )
    {
      if( currentSortDirection == SortDirection.None )
        return SortDirection.Ascending;

      if( currentSortDirection == SortDirection.Ascending )
        return SortDirection.Descending;

      return SortDirection.None;
    }

    private void RemoveAllContainers()
    {
      RemoveContainersVisitor visitor = new RemoveContainersVisitor( this );
      this.RootHost.Accept( visitor );
    }

    private void UpdateRootHostOffset()
    {
      double globalCellsOffset = this.GetColumnElementsIdentForDepth( 0 );
      this.RootHost.CellsIndent = globalCellsOffset;
      this.ColumnPanel.ColumnElementsIndent = globalCellsOffset;
    }

    private void UpdateRowsCellOffset()
    {
      RowVisitor rowVisitor = new RowVisitor( ChildrenPolicy.RenderedChildrenOnly, ( row ) => row.CellsOffset = this.GetColumnElementsIdentForDepth( 1 ) );
      this.DataGridPanel.Accept( rowVisitor );
    }













    private bool GetColumnInheritedAllowGroup( Column column )
    {
      return ( column != null )
        ? column.AllowGroup.GetValueOrDefault( this.AllowGroup )
        : this.AllowGroup;
    }







    private void OnFixedCollectionChanged( object sender, NotifyCollectionChangedEventArgs e )
    {
      ObservableCollection<UIElement> collection = sender as ObservableCollection<UIElement>;

      Debug.Assert( ( collection != null ) && ( ( collection == m_fixedHeaders ) || ( collection == m_fixedFooters ) ) );

      ObservableCollection<UIElement> listToPrepare = ( e.NewItems != null ) ? new ObservableCollection<UIElement>( e.NewItems.Cast<UIElement>() )
                                                                                : new ObservableCollection<UIElement>();
      ObservableCollection<UIElement> listToClear = ( e.OldItems != null ) ? new ObservableCollection<UIElement>( e.OldItems.Cast<UIElement>() )
                                                                                : new ObservableCollection<UIElement>();

      if( e.Action == NotifyCollectionChangedAction.Reset )
      {
        if( object.Equals( collection, m_fixedHeaders ) )
          this.FillFixedHeadersFootersListsOnReset( this.DataGridPanel.FixedHeaders, m_fixedHeaders, ref listToClear, ref listToPrepare );
        else 
          this.FillFixedHeadersFootersListsOnReset( this.DataGridPanel.FixedFooters, m_fixedFooters, ref listToClear, ref listToPrepare );
      }

      foreach( UIElement element in listToClear )
      {
        this.ClearHeaderFooterCore( element );
      }

      foreach( UIElement element in listToPrepare )
      {
        this.PrepareHeaderFooterCore( ( UIElement )element,
                                                ( m_fixedHeaders == sender ) ? LocationState.GridHeader : LocationState.GridFooter );

        this.ModifyStatContextForElement( element, DataGridControl.GetStatContext( this ) );
      }

      this.DataGridPanel.SetHeadersFooters( this.FixedHeaders, this.FixedFooters );

      this.DataGridPanel.InvalidateMeasure();
    }

    private void FillFixedHeadersFootersListsOnReset( IEnumerable<UIElement> oldFixedElements,
                                                     ObservableCollection<UIElement> currentFixedElements,
                                                     ref ObservableCollection<UIElement> listToClear,
                                                     ref ObservableCollection<UIElement> listToPrepare )
    {
      foreach( UIElement element in oldFixedElements )
      {
        if( !currentFixedElements.Contains( element ) )
          listToClear.Add( element );
      }
      foreach( UIElement element in currentFixedElements )
      {
        if( !oldFixedElements.Contains( element ) )
          listToPrepare.Add( element );
      }
    }

    private object UpdateCurrentInternal( DataPath oldPath, DataPath newPath )
    {
      return this.UpdateCurrentInternal( false, oldPath, newPath, false, null, null );
    }

    private object UpdateCurrentInternal( Column oldColumn, Column newColumn )
    {
      return this.UpdateCurrentInternal( false, null, null, false, oldColumn, newColumn );
    }

    private object UpdateCurrentInternal(
      bool setNewPath,
      DataPath oldPath,
      DataPath newPath,
      bool setNewColumn,
      Column oldColumn,
      Column newColumn )
    {
      if( m_changingCurrent.IsSet )
        return null;

      using( m_changingCurrent.Set() )
      {
        if( oldPath == null )
        {
          oldPath = this.CurrentDataPath;
        }

        if( oldColumn == null )
        {
          oldColumn = this.CurrentColumn;
        }

        if( setNewPath )
        {
          this.CurrentDataPath = newPath;
        }

        if( setNewColumn )
        {
          this.CurrentColumn = newColumn;
        }
        else if( newColumn == null )
        {
          newColumn = oldColumn;
        }

        bool rowChanged = !object.Equals( oldPath, newPath );
        if( rowChanged )
        {
          this.EndEditEditedRows( newPath );
        }

        bool columnChanged = !object.Equals( oldColumn, newColumn );
        if( columnChanged )
        {
          this.EndEditEditedCells( newPath, newColumn );
        }

        if( rowChanged || columnChanged )
        {
          this.RaiseCurrentCellChanged();
        }

        var currentElement = this.CurrentElement;
        if( currentElement is Row )
        {
          var currentCell = this.CurrentCell;
          if( currentCell != null )
            return currentCell;

          if( this.CurrentColumn == null )
            return currentElement;
        }
        else
        {
          return currentElement;
        }

        return null;
      }
    }

    private void EndEditEditedRows( DataPath excluded )
    {
      bool commitNewItem = ( excluded != null );

      foreach( EditableRowViewModel viewModel in ( from vm in m_dataGridViewModel.EditedRows
                                                   where ( !vm.IsNewItem || commitNewItem )
                                                      && ( !object.Equals( excluded, vm.DataPath ) )
                                                   select vm ).ToList() )
      {
        m_editingManager.EndEdit( viewModel );
      }
    }

    private void EndEditEditedCells( DataPath targetRow, Column excluded )
    {
      this.EndEditEditedRows( targetRow );

      foreach( EditableCellViewModel viewModel in ( from rvm in m_dataGridViewModel.EditedRows
                                                    where ( rvm.IsNewItem || object.Equals( targetRow, rvm.DataPath ) )
                                                    from cvm in rvm.Cells
                                                    where ( cvm.Column != excluded )
                                                    select cvm ).ToList() )
      {
        m_editingManager.EndEdit( viewModel );
      }
    }

    private double GetNormalizedColumnWidth( Column column )
    {
      var width = column.Width;
      var actualMinWidth = this.GetInheritedColumnMinWidth( column );
      var actualMaxWidth = this.GetInheritedColumnMaxWidth( column );

      if( width < actualMinWidth )
        return actualMinWidth;

      if( width > actualMaxWidth )
        return actualMaxWidth;

      return width;
    }

    private double GetInheritedColumnMinWidth( Column column )
    {
      if( ( column != null ) && column.MinWidth.HasValue )
        return column.MinWidth.Value;

      return this.MinColumnWidth;
    }

    private double GetInheritedColumnMaxWidth( Column column )
    {
      var actualMinWidth = this.GetInheritedColumnMinWidth( column );

      if( ( column != null ) && column.MaxWidth.HasValue )
      {
        // The ActualMinWidth will be used if it's greater.
        return Math.Max( actualMinWidth, column.MaxWidth.Value );
      }

      return Math.Max( actualMinWidth, this.MaxColumnWidth ); // The ActualMinWidth will be used if it's greater.
    }

    private void UpdateColumnsWidth()
    {
      foreach( Column column in this.DataGridContext.Columns )
      {
        this.UpdateColumnWidth( column );
      }
    }

    private void UpdateColumnWidth( Column column )
    {
      column.ActualWidth = this.GetNormalizedColumnWidth( column );
    }

    private ColumnContainer GetColumnContainer( Column column )
    {
      return this.DataGridPanel.RenderedColumns.FirstOrDefault( ( c ) => object.ReferenceEquals( c.Column, column ) );
    }

    private void OnColumnsCollectionChanged( object sender, NotifyCollectionChangedEventArgs e )
    {
      bool isInDesignMode = Xceed.Utils.Licensing.DesignerProperties.GetIsInDesignMode();

      switch( e.Action )
      {
        case NotifyCollectionChangedAction.Add:
          this.AddColumn( e.NewStartingIndex, e.NewItems[ 0 ] as Column );
          break;

        case NotifyCollectionChangedAction.Remove:
          this.RemoveColumn( e.OldItems[ 0 ] as Column );
          break;

        case NotifyCollectionChangedAction.Replace:
          break;

        case NotifyCollectionChangedAction.Reset:

          if( ( isInDesignMode ) && ( this.AutoCreateColumns ) )
          {
            //   Ensure that all autocreated columns are there
            //   but added after customer created ones.
            //  this.DataGridControl.Dispatcher.BeginInvoke(
            //    new Action( this.GenerateColumnsForDataSource ) );
          }

          break;
      }

      this.UpdateColumnsVisiblePosition();

      this.RefreshColumns( false );  //show new column
    }

    private void AddColumn( int index, Column column )
    {
      this.ValidateColumn( column );

      FieldDescriptor fieldDescriptor = this.GetFieldDescriptor( column.DisplayMemberBindingInfo.Path.Path );
      this.UpdateColumnWithFieldDescriptor( column, fieldDescriptor );

      //Set the binding of DataGrid.ColumnWidth -> Column.Width if no Width was set on column.
      //Done only when assigning columns
      if( column.ReadLocalValue( Column.WidthProperty ) == DependencyProperty.UnsetValue )
      {
        var binding = new Binding();
        binding.Source = this;
        binding.Path = new PropertyPath( "ColumnWidth" );
        binding.Mode = BindingMode.OneWay;

        // This binding will get overridden when a local value is set on the column.
        // For example, this will happen when the user resizes the column. This will force
        // the column to follow the ColumnWidth property on the DataGridControl until
        // a width for the column is specified.
        BindingOperations.SetBinding( column, Column.WidthProperty, binding );
      }

      // When a column is added (or inserted) without a VisiblePosition, set it to the ColumnColection's index.
      if( column.VisiblePosition == -1 )
      {
        column.VisiblePosition = index;
      }
      // Make sure all columns have different VisiblePositions
      this.UpdateColumnsVisiblePositionOnInsertion( column );

      foreach( SortDescription sort in this.SortDescriptions )
      {
        if( sort.PropertyName == column.SortFieldName )
        {
          column.SortDirection = ( sort.Direction == ListSortDirection.Ascending )
                                   ? SortDirection.Ascending
                                   : SortDirection.Descending;

          break;
        }
      }

      column.ActualWidth = this.GetNormalizedColumnWidth( column );

      this.SetDataSourceSorting( column.SortFieldName, column.SortDirection, true, true );

      this.RegisterColumn( column );
    }

    private void UpdateColumnsVisiblePositionOnInsertion( Column column )
    {
      Column referenceColumn = column;
      while( true )
      {
        bool modificationDone = false;

        // Parse each column and try to find a column with the same VisiblePosition
        // as the referenceColumn. Is found, increment its VisiblePosition. Continue until
        // each column has a different VisiblePosition.
        foreach( Column col in this.DataGridContext.Columns )
        {
          if( object.ReferenceEquals( col, referenceColumn ) )
            continue;

          if( col.VisiblePosition == referenceColumn.VisiblePosition )
          {
            // Unregister from PropertyChanged event when inserting a column so that modifying the column.VisiblePosition callback won't do anything
            col.PropertyChanged -= new PropertyChangedEventHandler( this.OnColumnPropertyChanged );
            col.VisiblePosition++;
            // Reregister to the PropertyChanged event
            col.PropertyChanged += new PropertyChangedEventHandler( this.OnColumnPropertyChanged );
            referenceColumn = col;
            modificationDone = true;
            break;
          }
        }

        if( !modificationDone )
          break;
      }
    }

    private void ValidateColumn( Column columnToValidate )
    {
      if( columnToValidate.DisplayMemberBinding == null )
      {
        throw new ArgumentException( "The Column.DisplayMemberBinding property must be set to a valid value.", "columnToValidate" );
      }

      if( string.IsNullOrEmpty( columnToValidate.FieldName ) )
      {
        throw new ArgumentException( "The Column.FieldName property must be set prior to adding the column to the collection.", "columnToValidate" );
      }
    }

    private FieldDescriptor GetFieldDescriptor( string fieldName )
    {
      return ItemsSourceHelper.GetField( this.DataGridContext.DataSource.ElementType, fieldName );
    }

    private void UpdateColumnValuesWithFieldDescriptor( Column column, string bindingPath, bool fieldDescriptorReadOnly )
    {
      if( column == null )
        throw new ArgumentNullException( "column" );

      if( bindingPath == null )
        return;

      Data.DataSourceProvider dataSourceProvider = this.DataGridContext.DataSource.Provider;
      if( dataSourceProvider == null )
        throw new InvalidOperationException( "The data-source provider cannot be null when updating a column with a field descriptor." );

      // Only affect the DisplayMemberBindingInfo if 
      // missing or if it is auto generated.
      if( ( column.DisplayMemberBindingInfo == null )
       || ( column.DisplayMemberBindingInfo.IsAutoGenerated ) )
      {
        bool readOnly = fieldDescriptorReadOnly || this.GetInheritedReadOnly( column );
        column.DisplayMemberBindingInfo = new DataGridBindingInfo( bindingPath, readOnly, true );
      }
    }

    private bool TryUpdateColumnValuesForComplexBindingPath( Column column, string bindingPath, Type entityType )
    {
      PropertyInfo propertyInfo = ComplexStringHelper.GetPropertyInfo( entityType, bindingPath );

      if( propertyInfo != null )
      {
        bool readOnly = ItemsSourceHelper.IsPropertyReadOnly( propertyInfo );
        this.UpdateColumnValuesWithFieldDescriptor( column, bindingPath, readOnly );

        return true;
      }
      return false;
    }

    private void RemoveColumn( Column column )
    {
      this.UnregisterColumn( column );
      //Clear binding
      column.ClearValue( Column.WidthProperty );
    }

    private void GenerateColumnsForDataSource()
    {
      Type entityType = this.DataGridContext.DataSource.ElementType;

      IDictionary<string, FieldDescriptor> fieldDescriptors = ItemsSourceHelper.GetFieldsForItemType( entityType );

      // For all columns defined in XAML
      foreach( Column column in this.DataGridContext.Columns )
      {
        FieldDescriptor descriptor = null;
        fieldDescriptors.TryGetValue( column.DisplayMemberBindingInfo.Path.Path, out descriptor );
        this.UpdateColumnWithFieldDescriptor( column, descriptor );
      }

      if( this.AutoCreateColumns )
      {
        var fieldDescriptorNames = new HashSet<string>();

        foreach( FieldDescriptor fieldDescriptor in fieldDescriptors.Values )
        {
          var name = fieldDescriptor.Name;

          fieldDescriptorNames.Add( name );

          // Look for the column with the descriptor name
          Column existingColumn = this.DataGridContext.Columns[ name ];

          if( existingColumn == null )
          {
            existingColumn = new Column();
            existingColumn.IsAutoGenerated = true;
            // The FieldName will be used to create the default DataGridBindingInfo that will be used
            // to update column values with the field descriptor, which will be overwritten because 
            // they were automatically created.
            existingColumn.FieldName = name;
            existingColumn.Title = fieldDescriptor.DisplayName;

            this.DataGridContext.Columns.Add( existingColumn );
          }
        }

        // Cleanup columns that were auto-generated but not needed anymore.
        var count = this.DataGridContext.Columns.Count;
        for( var i = count - 1; i >= 0; i-- )
        {
          var column = this.DataGridContext.Columns[ i ];

          if( ( column.IsAutoGenerated )
            && ( !fieldDescriptorNames.Contains( column.FieldName ) ) )
          {
            this.DataGridContext.Columns.RemoveAt( i );
          }
        }
      }
    }

    private void UpdateColumnWithFieldDescriptor( Column column, FieldDescriptor descriptor )
    {
      // Retrieve the descriptor (i.e., the column's binding path)
      if( descriptor != null )
      {
        this.UpdateColumnValuesWithFieldDescriptor( column, column.DisplayMemberBindingInfo.Path.Path, descriptor.ReadOnly );
      }
      else
      {
        this.TryUpdateColumnValuesForComplexBindingPath( column, column.DisplayMemberBindingInfo.Path.Path, this.DataGridContext.DataSource.ElementType );
      }
    }

    private void RemoveAutoGeneratedColumns()
    {
      Debug.Assert( Xceed.Utils.Licensing.DesignerProperties.GetIsInDesignMode() );

      ColumnCollection columns = this.DataGridContext.Columns;

      int columnCount = columns.Count;

      for( int i = columnCount - 1; i >= 0; i-- )
      {
        Column column = columns[ i ];

        if( column.IsAutoGenerated )
        {
          columns.RemoveAt( i );
        }
      }
    }

    private void OnItemsSourceChanged( object newItemsSource )
    {
      // We do not want to process the change now if the grid is initializing (ie. BeginInit/EndInit).
      m_hasPendingItemsSourceChanged = this.IsInitializing;

      if( this.IsInitializing )
        return;

      // Ensure to clear the CurrentItem and CurrentColumn before really changing
      // the ItemsSource.
      this.CurrentPath = null; //will set currentItem to null with binding

      if( ( this.DataGridContext.DataSource != null )
        && ( this.DataGridContext.DataSource.Provider != null )
        && ( this.DataGridContext.DataSource.Provider.GetType() != typeof( EmptyDataSourceProvider ) ) )
      {
        // Clear selection before changing the ItemsSource
        this.ClearAllSelections();
      }

      SavedDataSourceData savedDataSourceData = new SavedDataSourceData();

      //clean old stuff
      if( this.DataGridContext.DataSource != null )
        this.CleanUpDataSource( ref savedDataSourceData );

      m_dataGridViewModel.Clear();

      //this.CleanFixedRegions();

      this.DataGridContext.DataSource = this.GenerateDataSourceForObject( newItemsSource );

      this.SetupDataSource( savedDataSourceData );

      this.DataGridContext.DataSource.GroupStatFunctionsSelector = new GroupConfigurationSelectorAdapter( this );

      this.GenerateColumnsForDataSource();

      this.InvalidateData();
    }

    private void CleanUpDataSource( ref SavedDataSourceData savedDataSourceData )
    {
      // Save the data from the DataSource
      this.SaveDataSourceConfiguration( ref savedDataSourceData );

      this.DataGridContext.DataSource.ExpansionChanged -= new EventHandler<ExpansionChangedEventArgs>( this.OnDataSourceExpansionChanged );
      this.DataGridContext.DataSource.SourceChanged -= this.OnDataSourceChanged;

      if( this.DataGridContext.DataSource.Provider != null )
        this.DataGridContext.DataSource.Provider.UnhandledException -= OnDataSourceProviderUnhandledException;
    }

    private void SetupDataSource( SavedDataSourceData savedDataSourceData )
    {
      //Setup grouping and sorting and any pre-configured stuff on the data source.
      this.UpdateDataSourceConfiguration( savedDataSourceData );

      this.DataGridContext.DataSource.ExpansionChanged += new EventHandler<ExpansionChangedEventArgs>( this.OnDataSourceExpansionChanged );
      //register for change notification.
      this.DataGridContext.DataSource.SourceChanged += this.OnDataSourceChanged;

      Debug.Assert( this.DataGridContext.DataSource.Provider != null );
      this.DataGridContext.DataSource.Provider.UnhandledException += OnDataSourceProviderUnhandledException;
    }

    private DataGridDataSource GenerateDataSourceForObject( object newItemsSource )
    {
      // An empty data source or an unlicensed data grid shouldn't display
      // any data.
      if( newItemsSource == null )
      {
        return new DataGridDataSource( this.Dispatcher, new EmptyDataSourceProvider() );
      }

      DataGridDataSource dataSource = null;
      Xceed.Silverlight.Data.DataSourceProvider dataSourceProvider = null;

      newItemsSource = DataSourceWrapper.ConvertIfNeeded( newItemsSource );

      // A data source is available.
      if( newItemsSource is DataSourceWrapper )
      {
        dataSource = ( DataGridDataSource )newItemsSource;
        dataSourceProvider = dataSource.Provider;
      }
      else
      {
        DataSourceProviderFactory factory = new DataSourceProviderFactory();
        dataSourceProvider = factory.Create( newItemsSource );
      }

      // Make sure we haven't met an unknown data source.
      if( dataSourceProvider == null )
        throw new InvalidOperationException( "An attempt was made to use a data source that is not supported." );

      return ( dataSource != null )
               ? dataSource
               : new DataGridDataSource( this.Dispatcher, dataSourceProvider );
    }

    private void SaveDataSourceConfiguration( ref SavedDataSourceData savedDataSourceData )
    {
      savedDataSourceData.groupDescriptions = this.DataGridContext.GroupDescriptions;
      savedDataSourceData.sortDescriptions = this.DataGridContext.SortDescriptions;
    }

    private void UpdateDataSourceConfiguration( SavedDataSourceData savedDataSourceData )
    {
      if( savedDataSourceData.groupDescriptions != null )
      {
        foreach( var groupDescription in savedDataSourceData.groupDescriptions )
        {
          this.DataGridContext.GroupDescriptions.Add( groupDescription );
        }
      }

      if( savedDataSourceData.sortDescriptions != null )
      {
        foreach( var sortDescription in savedDataSourceData.sortDescriptions )
        {
          this.DataGridContext.SortDescriptions.Add( sortDescription );
        }
      }

      this.DataGridContext.DataSource.Filter = m_currentFilter;
      this.DataGridContext.UpdateSourceFilterExpression();
    }

    private IEnumerable<Column> GetFixedColumns( IEnumerable<Column> orderedColumns, bool left )
    {
      if( !left )
      {
        orderedColumns = orderedColumns.Reverse();
      }

      return orderedColumns
                .Where( ( col ) => col.Visible )
                .Take( left ? this.LeftFixedColumnCount : this.RightFixedColumnCount );
    }

    private IEnumerable<Column> GetScrollableColumns()
    {
      return this.GetScrollableColumns( this.GetOrderedColumns() );
    }

    private IEnumerable<Column> GetScrollableColumns( IEnumerable<Column> orderedColumns )
    {
      IEnumerable<Column> leftFixedColumn = this.GetFixedColumns( orderedColumns, true );
      IEnumerable<Column> rightFixedColumn = this.GetFixedColumns( orderedColumns, false );

      IEnumerable<Column> fixedcolumns = leftFixedColumn.Concat( rightFixedColumn );

      return orderedColumns.Where( ( col ) => !fixedcolumns.Contains( col ) && col.Visible );
    }

    private IEnumerable<Column> GetOrderedColumns()
    {
      ColumnCollection columnCollection = this.DataGridContext.Columns;

      return from column in columnCollection
             orderby column.VisiblePosition //"ascending" is default
             select column;
    }

    private bool IsColumnFixed( Column column )
    {
      IEnumerable<Column> orderedColumns = this.GetOrderedColumns();
      IEnumerable<Column> leftFixedColumns = this.GetFixedColumns( orderedColumns, true );
      IEnumerable<Column> rightFixedColumns = this.GetFixedColumns( orderedColumns, false );

      if( leftFixedColumns.Contains( column ) || rightFixedColumns.Contains( column ) )
        return true;

      return false;
    }

    private void UpdateHorizontalScrollBarVisibility()
    {
      Visibility horizontalScrollBarVisibility = Visibility.Collapsed;

      switch( this.HorizontalScrollBarVisibility )
      {
        case ScrollBarVisibility.Disabled:
          horizontalScrollBarVisibility = Visibility.Collapsed;
          break;
        case ScrollBarVisibility.Hidden:
          horizontalScrollBarVisibility = Visibility.Collapsed;
          break;
        case ScrollBarVisibility.Visible:
          horizontalScrollBarVisibility = Visibility.Visible;
          break;
        case ScrollBarVisibility.Auto:

          if( m_horizontalScrollBar.Maximum != m_horizontalScrollBar.Minimum )
          {
            horizontalScrollBarVisibility = Visibility.Visible;
          }

          break;
        default:
          throw new InvalidOperationException( "An attempt was made to update the horizontal scroll bar visibility with an unknown value." );
      }

      this.ComputedHorizontalScrollBarVisibility = horizontalScrollBarVisibility;
    }

    private void UpdateVerticalScrollBarVisibility()
    {
      Visibility verticalScrollBarVisibility = Visibility.Collapsed;

      switch( this.VerticalScrollBarVisibility )
      {
        case ScrollBarVisibility.Disabled:
          verticalScrollBarVisibility = Visibility.Collapsed;
          break;
        case ScrollBarVisibility.Hidden:
          verticalScrollBarVisibility = Visibility.Collapsed;
          break;
        case ScrollBarVisibility.Visible:
          verticalScrollBarVisibility = Visibility.Visible;
          break;
        case ScrollBarVisibility.Auto:

          if( m_verticalScrollBar.Maximum != m_verticalScrollBar.Minimum )
          {
            verticalScrollBarVisibility = Visibility.Visible;
          }

          break;
        default:
          throw new InvalidOperationException( "An attempt was made to update the vertical scroll bar visibility with an unknown value." );
      }

      this.ComputedVerticalScrollBarVisibility = verticalScrollBarVisibility;
    }

    private void OnDataSourceProviderUnhandledException( object sender, UnhandledDataExceptionEventArgs e )
    {
      this.OnUnhandledDataException( e );
    }

    private void StatFunctionsCollectionChanged( object sender, NotifyCollectionChangedEventArgs e )
    {
      this.ResetStatContext();
    }

    private void ProcessInitializationParameters()
    {
      if( this.IsInitializing )
        throw new DataGridInternalException(); //Method should not get invoked while still in a BeginInit/EndInit block.

      this.UpdateEnumerator();

      object itemsSource = this.ItemsSource;

      // If the ItemsSource was changed during the initialization process, process it here.
      if( m_hasPendingItemsSourceChanged )
      {
        //This will trigger creation of a DataSource based on the actual config.
        this.OnItemsSourceChanged( itemsSource );
      }

      this.UpdateColumnsVisiblePosition();
    }

    internal void ModifyStatContextForElement( DependencyObject element, StatContext newStatContext )
    {
      element.ClearValue( DataGridControl.StatContextProperty );
      DataGridControl.SetStatContext( element, newStatContext );
    }

    internal void ModifyGroupContextForElement( DependencyObject element, GroupContext newGroupContext )
    {
      element.ClearValue( DataGridControl.GroupContextProperty );
      DataGridControl.SetGroupContext( element, newGroupContext );
    }

    internal bool IsCurrentElement( IDataGridElement element )
    {
      if( element == null )
        throw new ArgumentNullException( "element" );

      return this.IsCurrentPath( element.Path );
    }

    internal bool IsCurrentPath( DataPath path )
    {
      if( path == null )
        throw new ArgumentNullException( "path" );

      return ( this.CurrentPath != null ) && object.Equals( path, this.CurrentPath.ActualDataPath );
    }

    internal bool IsCurrentCell( Cell cell, bool? isFromCurrentRow, bool? isFromCurrentColumn )
    {
      if( isFromCurrentRow.HasValue && !isFromCurrentRow.Value )
        return false;

      if( isFromCurrentColumn.HasValue && !isFromCurrentColumn.Value )
        return false;

      if( cell.ParentColumnContainer.IsRecycled )
        return false;

      if( !isFromCurrentColumn.HasValue )
      {
        if( !object.Equals( cell.ParentColumn, this.CurrentColumn ) )
          return false;
      }

      if( !isFromCurrentRow.HasValue )
      {
        if( !this.IsCurrentElement( cell.ParentRow ) )
          return false;
      }

      return true;
    }

    internal object UpdateRowCurrentState( Row row, bool? isCurrentRow, bool useTransition )
    {
      object currentElement = null;

      bool isCurrent = ( isCurrentRow.HasValue ) ? isCurrentRow.Value : this.IsCurrentElement( row );

      row.SetCurrentState( isCurrent, useTransition );

      //Update the current state for the cells. The cells current state
      //depend on both DataPath, and column.
      foreach( Cell cell in row.RenderedCells )
      {
        if( this.UpdateCellCurrentState( cell, isCurrent, useTransition ) )
        {
          currentElement = cell;
        }
      }

      if( isCurrent && this.CurrentColumn == null )
      {
        currentElement = row;
      }

      return currentElement;

    }

    internal bool UpdateCellCurrentState( Cell cell, bool? isCurrentRow, bool useTransition )
    {
      bool isCurrent = this.IsCurrentCell( cell, isCurrentRow, null );
      cell.SetCurrentState( isCurrent, useTransition );

      return isCurrent;
    }

    internal void EnsureCurrentIsFocused( object currentElement )
    {
      Control currentControl = currentElement as Control;
      if( currentControl != null )
      {
        DependencyObject focusScopeLimit = this;
        currentControl.EnsureHasFocus( focusScopeLimit );
      }
    }

    private void OnDataGridPanelUnconstrainedStateChanged( object sender, EventArgs e )
    {
      this.SetUnconstrainedState( true );
    }

    private void SetUnconstrainedState( bool isUnconstrained )
    {
      this.VisualStateHelper.GoToUnconstrainedState( isUnconstrained
                                                     ? DataGridControl.UnconstrainedStateUnconstrained
                                                     : DataGridControl.UnconstrainedStateConstrained, true );
    }

    private void OnDataGridPanelMouseWheel( object sender, MouseWheelEventArgs e )
    {
      e.Handled = true;

      if( m_verticalScrollBar == null )
        return;

      if( m_enumerator == null )
        return;

      double scrollTravel = -MouseHelper.GetLineScrolledCount( e );

      if( !this.CanExecuteMouseWheel( scrollTravel ) )
        return;

      if( Math.Abs( scrollTravel ) >= Double.Epsilon )
      {
        this.OnScroll( new ScrollEventArgs( ScrollEventType.ThumbTrack, m_verticalScrollBar.Value + scrollTravel ),
                       ref m_lastVerticalValue,
                       this.SetData,
                       true );
      }
    }

    private bool CanExecuteMouseWheel( double scrollTravel )
    {
      DataPath firstDataPath = null;
      DataPath lastDataPath = null;
      List<ILayoutElement> renderedElementList = this.RootContainer.RenderedElements.ToList();

      RowWrapper wrapper = renderedElementList.First() as RowWrapper;
      if( wrapper != null )
      {
        firstDataPath = ( ( Row )wrapper.Child ).Path;
      }
      wrapper = renderedElementList.Last() as RowWrapper;
      if( wrapper != null )
      {
        lastDataPath = ( ( Row )wrapper.Child ).Path;
      }

      return ( ( ( scrollTravel > 0 ) && !this.IsLastGridItem( lastDataPath ) )
              || ( ( scrollTravel < 0 ) && !this.IsFirstGridItem( firstDataPath ) ) );
    }

    private bool IsFirstGridItem( DataPath dataPath )
    {
      if( ( dataPath == null ) || dataPath.IsStubPath() )
        return false;

      if( this.IsDataSourceAsynchronous )
      {
        PeekParameters peekParams = new PeekParameters( new ItemPosition( dataPath ), -1, 1 );
        PeekResult<DataPath> peekResult = m_enumerator.Peek( peekParams );

        return ( (peekResult.PeekedItems == null) &&
                peekResult.EndPositionObject.IsBeforeFirst);
      }

      JumpMoveAndFetchParameters parameters = new JumpMoveAndFetchParameters( new ItemPosition( dataPath ), -1, 1 );
      Nullable<long> actualMoveCount;
      ICollection fetchedObjects;
      SourcePosition endPosition;
      RelativeOffset endPositionOffset;
      EstimateInt64 totalCount;
      m_enumerator.SyncJumpMoveAndFetch( parameters, out actualMoveCount, out fetchedObjects, out endPosition, out endPositionOffset, out totalCount );

      return ( fetchedObjects == null );
    }

    private bool IsLastGridItem( DataPath dataPath )
    {
      if( ( dataPath == null ) || dataPath.IsStubPath() )
        return false;

      if( this.IsDataSourceAsynchronous )
      {
        PeekParameters peekParams = new PeekParameters( new ItemPosition( dataPath ), 1, 1 );
        PeekResult<DataPath> peekResult = m_enumerator.Peek( peekParams );

        return ( ( peekResult.PeekedItems == null ) &&
                peekResult.EndPositionObject.IsAfterLast );
      }

      JumpMoveAndFetchParameters parameters = new JumpMoveAndFetchParameters( new ItemPosition( dataPath ), 1, 1 );
      Nullable<long> actualMoveCount;
      ICollection fetchedObjects;
      SourcePosition endPosition;
      RelativeOffset endPositionOffset;
      EstimateInt64 totalCount;
      m_enumerator.SyncJumpMoveAndFetch( parameters, out actualMoveCount, out fetchedObjects, out endPosition, out endPositionOffset, out totalCount );

      return ( fetchedObjects == null );
    }

    private Type GetColumnDataType( Column column )
    {
      if( column == null )
        return null;

      Type dataType = column.DisplayDataType;
      if( dataType != null )
        return dataType;

      var bindingInfo = column.DisplayMemberBindingInfo;
      if( bindingInfo == null )
        return null;

      var propertyPath = bindingInfo.Path;
      if( propertyPath == null )
        return null;

      dataType = this.GetPropertyPathDataType( propertyPath.Path );
      column.DisplayDataType = dataType;

      return dataType;
    }

    private Type GetPropertyPathDataType( string propertyPath )
    {
      if( string.IsNullOrEmpty( propertyPath ) )
        return null;

      var dataSource = this.DataGridContext.DataSource;
      if( dataSource == null )
        return null;

      var entityType = dataSource.ElementType;

      bool isNullable;
      var propertyPathExpression = ComplexStringHelper.GetExpressionFromString(
                                      propertyPath,
                                      entityType,
                                      System.Linq.Expressions.Expression.Parameter( entityType ),
                                      false,
                                      out isNullable );
      if( propertyPathExpression == null )
        return null;

      return propertyPathExpression.Type;
    }

    List<FilterExpressionBase> IDataGridContextHelper.GetFilterRowsExpressions()
    {
      List<FilterExpressionBase> expressionsList = new List<FilterExpressionBase>();



      return expressionsList;
    }

    private void UpdateElementsCurrentState( DataPath oldPath, DataPath newPath )
    {
      UIElement oldCurrentElement = this.GetContainerFromPath( oldPath );
      if( oldCurrentElement != null )
      {
        if( oldCurrentElement is Row )
        {
          Row oldCurrentRow = this.GetContainerFromPath( oldPath ) as Row;
          oldCurrentRow.SetCurrentState( false, true );

          Cell oldCurrentCell = oldCurrentRow.RenderedCells
                                  .FirstOrDefault( ( c ) => object.Equals( c.ParentColumn, this.CurrentColumn ) );
          if( oldCurrentCell != null )
          {
            oldCurrentCell.SetCurrentState( false, true );
          }
        }
        else if( oldCurrentElement is GroupHeaderControl )
        {
          GroupHeaderControl oldCurrentGroup = this.GetContainerFromPath( oldPath ) as GroupHeaderControl;
          oldCurrentGroup.SetCurrentState( false, true );
        }
      }
      UIElement newCurrentElement = this.GetContainerFromPath( newPath );
      if( newCurrentElement != null )
      {
        if( newCurrentElement is Row )
        {
          Row newCurrentRow = this.GetContainerFromPath( newPath ) as Row;
          newCurrentRow.SetCurrentState( true, true );

          Cell newCurrentCell = this.CurrentCell;
          if( newCurrentCell != null )
          {
            newCurrentCell.SetCurrentState( true, true );
          }
        }
        else if( newCurrentElement is GroupHeaderControl )
        {
          GroupHeaderControl newCurrentGroup = this.GetContainerFromPath( newPath ) as GroupHeaderControl;
          newCurrentGroup.SetCurrentState( true, true );
        }
      }
    }

    private void UpdateElementsCurrentState( Column oldColumn )
    {
      UIElement currentElement = this.CurrentElement;
      if( currentElement != null )
      {
        if( currentElement is Row )
        {
          Row currentRow = currentElement as Row;
          Cell oldCurrentCell = currentRow.RenderedCells
                                 .FirstOrDefault( ( c ) => object.Equals( c.ParentColumn, oldColumn ) );
          if( oldCurrentCell != null )
          {
            oldCurrentCell.SetCurrentState( false, true );
          }

          Cell newCurrentCell = this.CurrentCell;
          if( newCurrentCell != null )
          {
            newCurrentCell.SetCurrentState( true, true );
          }
        }
      }
    }

    #region INotifyPropertyChanged Implementation

    public event PropertyChangedEventHandler PropertyChanged;

    protected void RaisePropertyChanged( string name )
    {
      Xceed.Silverlight.DataGrid.Utils.ReflectionHelper.ValidatePublicPropertyName( this, name );

      if( this.PropertyChanged != null )
      {
        this.PropertyChanged( this, new PropertyChangedEventArgs( name ) );
      }
    }

    #endregion

    #region ISupportInitialize Members

    public void BeginInit()
    {
      m_initializationCount++;
    }

    public void EndInit()
    {
      if( --m_initializationCount == 0 )
      {
        this.ProcessInitializationParameters();
      }
    }

    private int m_initializationCount;

    #endregion

    #region Private Fields

    private readonly InhibitorFlag m_changingCurrent = new InhibitorFlag();
    private IPeekableEnumerator<DataPath> m_enumerator;
    private ScrollBar m_verticalScrollBar;
    private ScrollBar m_horizontalScrollBar;
    private Border m_dataGridPanelHost;
    private double m_lastVerticalValue = 0d;
    private double m_lastHorizontalValue = 0d;
    private readonly RowUpdateManager m_rowUpdateManager;
    private readonly ColumnUpdateManager m_columnUpdateManager;
    private readonly EditingManager m_editingManager;
    private readonly DataGridViewModel m_dataGridViewModel;
    private ObservableCollection<UIElement> m_fixedHeaders;
    private ObservableCollection<UIElement> m_fixedFooters;
    private Predicate<object> m_currentFilter;
    private HardwareEventsManager m_hardwareEventManager;
    private bool m_hasPendingItemsSourceChanged; // false
    private int m_deferUpdateCount;

    #endregion

    #region FilterExpressionParserResult Nested Type

    private sealed class FilterExpressionParserResult
    {
      private FilterExpressionParserResult(
        Exception exception,
        IEnumerable<KeyValuePair<string, FilterExpression>> filterExpressions )
      {
        m_exception = exception;

        var results = FilterExpressionParserResult.Coerce( filterExpressions );
        m_filterExpressions = results.ToLookup( ( item ) => item.Key, ( item ) => item.Value );
      }

      internal bool HasError
      {
        get
        {
          return ( m_exception != null );
        }
      }

      internal Exception Error
      {
        get
        {
          return m_exception;
        }
      }

      internal ILookup<string, FilterExpression> FilterExpressions
      {
        get
        {
          return m_filterExpressions;
        }
      }

      internal static FilterExpressionParserResult Success()
      {
        return FilterExpressionParserResult.Success( null );
      }

      internal static FilterExpressionParserResult Success( IEnumerable<KeyValuePair<string, FilterExpression>> filterExpressions )
      {
        return new FilterExpressionParserResult( null, filterExpressions );
      }

      internal static FilterExpressionParserResult Failure( Exception exception )
      {
        return FilterExpressionParserResult.Failure( null, null );
      }

      internal static FilterExpressionParserResult Failure( Exception exception, IEnumerable<KeyValuePair<string, FilterExpression>> filterExpressions )
      {
        if( exception == null )
          throw new ArgumentNullException( "exception" );

        return new FilterExpressionParserResult( exception, filterExpressions );
      }

      private static IEnumerable<KeyValuePair<string, FilterExpression>> Coerce( IEnumerable<KeyValuePair<string, FilterExpression>> items )
      {
        if( items == null )
          return Enumerable.Empty<KeyValuePair<string, FilterExpression>>();

        return items;
      }

      private readonly Exception m_exception;
      private readonly ILookup<string, FilterExpression> m_filterExpressions;
    }

    #endregion

    #region FilterExpressionParser Nested Type

    private sealed class FilterExpressionParser
    {
      internal FilterExpressionParser( DataGridControl dataGrid, FilterExpressionBase filterExpression )
      {
        if( dataGrid == null )
          throw new ArgumentNullException( "dataGrid" );

        m_dataGrid = dataGrid;
        m_filterExpression = filterExpression;
      }

      internal FilterExpressionParserResult Parse()
      {
        if( m_filterExpression == null )
          return FilterExpressionParserResult.Success();

        m_errors.Clear();
        m_parsedParts.Clear();

        if( m_filterExpression is FilterExpression )
        {
          this.Parse( ( FilterExpression )m_filterExpression );
        }
        else if( m_filterExpression is AndFilterExpression )
        {
          var children = ( ( AndFilterExpression )m_filterExpression ).ChildExpressions;
          foreach( var child in children )
          {
            var part = child as FilterExpression;

            if( part != null )
            {
              this.Parse( part );
            }
            else
            {
              m_errors.Add( new InvalidOperationException( "An invalid FilterExpression has been provided." ) );
            }
          }
        }
        else
        {
          m_errors.Add( new InvalidOperationException( "An invalid FilterExpression has been provided." ) );
        }

        if( m_errors.Count > 0 )
          return FilterExpressionParserResult.Failure( m_errors[ 0 ], m_parsedParts );

        return FilterExpressionParserResult.Success( m_parsedParts );
      }

      private void Parse( FilterExpression part )
      {
        // A FilterCell cannot display correctly a null value.
        if( part.Value == null )
        {
          // The FilterExpression.Value property must not be null.
          m_errors.Add( new ArgumentException( "The FilterExpression must specify a non-null value.", "part" ) );
          return;
        }

        // Retrieve the data type of the field being referenced.
        var valueType = m_dataGrid.GetPropertyPathDataType( part.MemberName );

        // For a string value, the filter expression's case sensitivity must be specified.
        if( ( typeof( string ) == valueType ) && !part.IsCaseSensitive.HasValue )
        {
          // The FilterExpression.IsCaseSensitive property must not be set if the FilterExpression is targeting a string column.
          m_errors.Add( new InvalidOperationException( "A FilterExpression with a String value must set the IsCaseSensitive property." ) );
          return;
        }

        // For a date time value, the filter expression must be time insensitive.
        if( ( ( typeof( DateTime ) == valueType ) || ( typeof( DateTime? ) == valueType ) )
          && part.IsTimeSensitive.GetValueOrDefault( true ) )
        {
          // The FilterExpression.IsTimeSensitive property must be set to false if the FilterExpression is targeting a DateTime column.
          m_errors.Add( new InvalidOperationException( "A FilterExpression with a DateTime value must set the IsTimeSensitive property to false." ) );
          return;
        }

        var targetColumn = ( from column in m_dataGrid.Columns
                             where column.DisplayMemberBindingInfo.Path.Path == part.MemberName
                             select column ).FirstOrDefault();
        if( targetColumn != null )
        {
          var fieldName = targetColumn.FieldName;

          // A FilterCell can only display a single FilterExpression.
          if( m_parsedParts.ContainsKey( fieldName ) )
          {
            m_errors.Add( new InvalidOperationException( "An invalid FilterExpression has been provided." ) );
            return;
          }

          m_parsedParts.Add( fieldName, part );
        }
      }

      private readonly DataGridControl m_dataGrid;
      private readonly FilterExpressionBase m_filterExpression;
      private readonly List<Exception> m_errors = new List<Exception>( 0 );
      private readonly Dictionary<string, FilterExpression> m_parsedParts = new Dictionary<string, FilterExpression>();
    }

    #endregion

    #region DeferRefreshHelper class

    private class DeferUpdateHelper : IDisposable
    {
      internal DeferUpdateHelper( DataGridControl datagrid )
      {
        m_datagrid = datagrid;
        Interlocked.Increment( ref m_datagrid.m_deferUpdateCount );
      }

      #region IDisposable Members

      public void Dispose()
      {
        this.Dispose( true );
        GC.SuppressFinalize( this );
      }

      protected virtual void Dispose( bool disposing )
      {
        lock( m_lock )
        {
          // Prevent the method from being executed more than once.
          if( m_disposed )
            return;

          m_disposed = true;
        }

        // The viewport content must not be updated yet.
        if( Interlocked.Decrement( ref m_datagrid.m_deferUpdateCount ) != 0 )
          return;

        m_datagrid.Dispatcher.BeginInvoke( () =>
                                                       {
                                                         m_datagrid.RefreshColumns(true);
                                                         m_datagrid.RefreshData(true);
        } );
      }

      ~DeferUpdateHelper()
      {
        this.Dispose( false );
      }

      private bool m_disposed; //false

      #endregion

      private DataGridControl m_datagrid;
      private object m_lock = new object();
    }

    #endregion
  }
}
